Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Commit

Permalink
Fixed grid component, async headings (#1259)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackbaud-SteveBrush authored Nov 6, 2017
1 parent 0407542 commit 557a4b3
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 47 deletions.
7 changes: 7 additions & 0 deletions src/modules/grid/fixtures/grid-async.component.fixture.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<sky-grid fit="scroll" [data]="items">
<sky-grid-column
id="column1"
field="column1"
[heading]="asyncHeading | async">
</sky-grid-column>
</sky-grid>
24 changes: 24 additions & 0 deletions src/modules/grid/fixtures/grid-async.component.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Component } from '@angular/core';

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Component({
selector: 'sky-test-cmp',
templateUrl: './grid-async.component.fixture.html'
})
export class GridAsyncTestComponent {
public items: Array<any> = [
{ 'id': 1, 'name': 'Windstorm', 'email': 'windstorm@gmail.com' },
{ 'id': 2, 'name': 'Bombasto', 'email': 'bombasto@gmail.com' },
{ 'id': 3, 'name': 'Magneta', 'email': 'magenta@gmail.com' },
{ 'id': 4, 'name': 'Tornado', 'email': 'tornado@gmail.com' }
];

public asyncHeading = new BehaviorSubject<string>(undefined);

constructor() {
setTimeout(() => {
this.asyncHeading.next('updated');
}, 100);
}
}
7 changes: 5 additions & 2 deletions src/modules/grid/fixtures/grid-fixtures.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { SkyGridModule } from '../';
import { GridTestComponent } from './grid.component.fixture';
import { GridEmptyTestComponent } from './grid-empty.component.fixture';
import { GridDynamicTestComponent } from './grid-dynamic.component.fixture';
import { GridAsyncTestComponent } from './grid-async.component.fixture';

@NgModule({
declarations: [
GridTestComponent,
GridEmptyTestComponent,
GridDynamicTestComponent
GridDynamicTestComponent,
GridAsyncTestComponent
],
imports: [
CommonModule,
Expand All @@ -20,7 +22,8 @@ import { GridDynamicTestComponent } from './grid-dynamic.component.fixture';
exports: [
GridTestComponent,
GridEmptyTestComponent,
GridDynamicTestComponent
GridDynamicTestComponent,
GridAsyncTestComponent
]
})
export class GridFixturesModule { }
36 changes: 30 additions & 6 deletions src/modules/grid/grid-column.component.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import {
ChangeDetectionStrategy,
Component,
Input,
ContentChildren,
EventEmitter,
Input,
OnChanges,
SimpleChanges,
TemplateRef,
QueryList,
ChangeDetectionStrategy
QueryList
} from '@angular/core';

@Component({
selector: 'sky-grid-column',
template: '<ng-content></ng-content>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SkyGridColumnComponent {
export class SkyGridColumnComponent implements OnChanges {
@Input()
public id: string;

@Input()
public heading: string;

@Input()
public width: number;

@Input()
public hidden: boolean;

@Input()
public locked: boolean;

@Input()
public field: string;

@Input()
public type: string;

@Input()
public description: string;

@Input()
public isSortable: boolean = true;

Expand All @@ -40,15 +51,28 @@ export class SkyGridColumnComponent {
public templateInput: TemplateRef<any>;
/* tslint:enable:no-input-rename */

public headingChanges: EventEmitter<string> = new EventEmitter<string>();

@ContentChildren(TemplateRef)
private templates: QueryList<TemplateRef<any>>;

public ngOnChanges(changes: SimpleChanges) {
if (changes.heading && changes.heading.firstChange === false) {
this.heading = changes.heading.currentValue;
this.headingChanges.emit(this.heading);
}
}

public get template(): TemplateRef<any> {
return (this.templates.length > 0 ? this.templates.first : undefined) || this.templateInput;
if (this.templates.length > 0) {
return this.templates.first;
}

return this.templateInput;
}

private search(value: any, searchText: string): boolean {
/* tslint:disable */
/* tslint:disable:no-null-keyword */
if (value !== undefined && value !== null) {
return value.toString().toLowerCase().indexOf(searchText) !== -1;
}
Expand Down
39 changes: 39 additions & 0 deletions src/modules/grid/grid.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import {
import {
GridDynamicTestComponent
} from './fixtures/grid-dynamic.component.fixture';

import { GridAsyncTestComponent } from './fixtures/grid-async.component.fixture';

import {
SkyGridModule,
SkyGridComponent,
Expand Down Expand Up @@ -702,4 +705,40 @@ describe('Grid Component', () => {
});
});

describe('async headings', () => {
it('should handle async column headings', (done: any) => {
let component: GridAsyncTestComponent;
let fixture: ComponentFixture<GridAsyncTestComponent>;
let nativeElement: HTMLElement;
let element: DebugElement;

TestBed.configureTestingModule({
imports: [
GridFixturesModule,
SkyGridModule
]
});

fixture = TestBed.createComponent(GridAsyncTestComponent);
nativeElement = fixture.nativeElement as HTMLElement;
element = fixture.debugElement as DebugElement;
component = fixture.componentInstance;

fixture.detectChanges();

expect(getColumnHeader('column1', element).nativeElement.textContent.trim())
.toBe('');

fixture.detectChanges();

setTimeout(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(getColumnHeader('column1', element).nativeElement.textContent.trim())
.toBe('updated');
done();
});
}, 110);
});
});
});
105 changes: 66 additions & 39 deletions src/modules/grid/grid.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Component,
Input,
OnDestroy,
Output,
ContentChildren,
QueryList,
Expand All @@ -11,18 +12,22 @@ import {
EventEmitter,
OnChanges
} from '@angular/core';

import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';

import { DragulaService } from 'ng2-dragula/ng2-dragula';

import {
ListItemModel,
ListSortFieldSelectorModel
} from '../list/state';

import { SkyGridColumnComponent } from './grid-column.component';
import { SkyGridColumnModel } from './grid-column.model';
import { ListItemModel } from '../list/state';
import { SkyGridAdapterService } from './grid-adapter.service';

import { ListSortFieldSelectorModel } from '../list/state';

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { Observable } from 'rxjs/Observable';

@Component({
selector: 'sky-grid',
templateUrl: './grid.component.html',
Expand All @@ -33,8 +38,7 @@ import { Observable } from 'rxjs/Observable';
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SkyGridComponent implements AfterContentInit, OnChanges {

export class SkyGridComponent implements AfterContentInit, OnChanges, OnDestroy {
@Input()
public selectedColumnIds: Array<string>;

Expand Down Expand Up @@ -65,21 +69,27 @@ export class SkyGridComponent implements AfterContentInit, OnChanges {
@Output()
public sortFieldChange = new EventEmitter<ListSortFieldSelectorModel>();

public displayedColumns: Array<SkyGridColumnModel> = new Array<SkyGridColumnModel>();

public items: Array<any> = new Array<any>();
public items: Array<any>;
public displayedColumns: Array<SkyGridColumnModel>;
public currentSortField: BehaviorSubject<ListSortFieldSelectorModel>;

public currentSortField: BehaviorSubject<ListSortFieldSelectorModel>
= new BehaviorSubject<ListSortFieldSelectorModel>({ fieldSelector: '', descending: false });

@ContentChildren(SkyGridColumnComponent, {descendants: true})
@ContentChildren(SkyGridColumnComponent, { descendants: true })
private columnComponents: QueryList<SkyGridColumnComponent>;

private subscriptions: Subscription[] = [];

constructor(
private dragulaService: DragulaService,
private ref: ChangeDetectorRef,
private gridAdapter: SkyGridAdapterService
) {}
) {
this.displayedColumns = new Array<SkyGridColumnModel>();
this.items = new Array<any>();
this.currentSortField = new BehaviorSubject<ListSortFieldSelectorModel>({
fieldSelector: '',
descending: false
});
}

public ngAfterContentInit() {
if (this.columnComponents.length !== 0 || this.columns !== undefined) {
Expand All @@ -90,22 +100,27 @@ export class SkyGridComponent implements AfterContentInit, OnChanges {
}

this.transformData();

this.setDisplayedColumns(true);
}

this.columnComponents.changes.subscribe((columnComponents) => {
this.getColumnsFromComponent();
this.setDisplayedColumns(true);
this.ref.markForCheck();
// Watch for added/removed columns:
this.subscriptions.push(
this.columnComponents.changes.subscribe(() => this.updateColumns())
);

// Watch for column heading changes:
this.columnComponents.forEach((comp: SkyGridColumnComponent) => {
this.subscriptions.push(
comp.headingChanges.subscribe(() => this.updateColumns())
);
});

this.gridAdapter.initializeDragAndDrop(
this.dragulaService,
(selectedColumnIds: Array<string>) => {
this.onHeaderDrop(selectedColumnIds);
}
);
this.dragulaService,
(selectedColumnIds: Array<string>) => {
this.onHeaderDrop(selectedColumnIds);
}
);
}

// Do an ngOnChanges where changes to selectedColumnIds and data are watched
Expand All @@ -125,6 +140,12 @@ export class SkyGridComponent implements AfterContentInit, OnChanges {
}
}

public ngOnDestroy() {
this.subscriptions.forEach((subscription: Subscription) => {
subscription.unsubscribe();
});
}

public sortByColumn(column: SkyGridColumnModel) {
if (column.isSortable) {
this.currentSortField
Expand Down Expand Up @@ -158,17 +179,17 @@ export class SkyGridComponent implements AfterContentInit, OnChanges {
}

private onHeaderDrop(newColumnIds: Array<string>) {
// update selected columnIds
this.selectedColumnIds = newColumnIds;
this.selectedColumnIdsChange.emit(newColumnIds);
// update selected columnIds
this.selectedColumnIds = newColumnIds;
this.selectedColumnIdsChange.emit(newColumnIds);

// set new displayed columns
this.displayedColumns = this.selectedColumnIds.map(
columnId => this.columns.filter(column => column.id === columnId)[0]
);
// set new displayed columns
this.displayedColumns = this.selectedColumnIds.map(
columnId => this.columns.filter(column => column.id === columnId)[0]
);

// mark for check because we are using ChangeDetectionStrategy.onPush
this.ref.markForCheck();
// mark for check because we are using ChangeDetectionStrategy.onPush
this.ref.markForCheck();
}

private setDisplayedColumns(respectHidden: boolean = false) {
Expand Down Expand Up @@ -200,8 +221,14 @@ export class SkyGridComponent implements AfterContentInit, OnChanges {
}

private getColumnsFromComponent() {
this.columns = this.columnComponents.map(columnComponent => {
return new SkyGridColumnModel(columnComponent.template, columnComponent);
});
this.columns = this.columnComponents.map(columnComponent => {
return new SkyGridColumnModel(columnComponent.template, columnComponent);
});
}

private updateColumns() {
this.getColumnsFromComponent();
this.setDisplayedColumns(true);
this.ref.markForCheck();
}
}

0 comments on commit 557a4b3

Please sign in to comment.