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

Commit

Permalink
List view grid column change event (#1897)
Browse files Browse the repository at this point in the history
Added event for watching for column change events on a list view gird. Also fixed issue where grids were not emitting their event at the correct time.

Resolves #1092
  • Loading branch information
Blackbaud-TrevorBurch authored Aug 15, 2018
1 parent 79d7288 commit b84e1b8
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 54 deletions.
16 changes: 14 additions & 2 deletions src/modules/grid/grid.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,19 @@ describe('Grid Component', () => {

});

it('should change displayed headers and data when selected columnids change', () => {
it('should change displayed headers and data when selected columnids change and emit the change event', async(() => {
component.grid.selectedColumnIdsChange.subscribe((newSelectedColumnIds: string[]) => {
expect(newSelectedColumnIds).toEqual([
'column1',
'column2',
'column3',
'column4',
'column5',
'hiddenCol1',
'hiddenCol2'
]);
});

component.selectedColumnIds = [
'column1',
'column2',
Expand All @@ -221,7 +233,7 @@ describe('Grid Component', () => {

verifyHeaders(true);
verifyData(false, true);
});
}));

it('should show all columns when selectedColumnIds is undefined', () => {
component.selectedColumnIds = undefined;
Expand Down
3 changes: 3 additions & 0 deletions src/modules/grid/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ export class SkyGridComponent implements AfterContentInit, OnChanges, OnDestroy
this.setDisplayedColumns(true);
} else if (changes['selectedColumnIds'] && this.columns) {
this.setDisplayedColumns();
if (changes['selectedColumnIds'].previousValue !== changes['selectedColumnIds'].currentValue) {
this.selectedColumnIdsChange.emit(this.selectedColumnIds);
}
}

if (changes['data'] && this.data) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Component } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { SkyListViewGridComponent } from '../list-view-grid.component';

@Component({
selector: 'sky-test-cmp',
template: require('./list-view-grid-dynamic.component.fixture.html')
})
export class ListViewGridDynamicTestComponent {

@ViewChild(SkyListViewGridComponent)
public grid: SkyListViewGridComponent;
public data: Array<any>;
public gridColumns: Array<any>;
constructor() {
Expand All @@ -22,7 +26,16 @@ export class ListViewGridDynamicTestComponent {
{ 'id': 2, 'field': 'email', 'heading': 'Email' }];
}

public changeColumnsDifferent() {
this.gridColumns = [{ 'id': 3, 'field': 'other', 'heading': 'Other' }];
public changeColumnsNameAndOther() {
this.gridColumns = [{ 'id': 1, 'field': 'name', 'heading': 'Name' }, { 'id': 3, 'field': 'other', 'heading': 'Other' }];
}

public changeColumnsOther() {
this.gridColumns = [{ 'id': 3, 'field': 'other', 'heading': 'Other' }];
}

public changeColumnsSame() {
this.gridColumns = [{ 'id': 1, 'field': 'name', 'heading': 'Name Initial' },
{ 'id': 2, 'field': 'email', 'heading': 'Email Initial' }];
}
}
71 changes: 54 additions & 17 deletions src/modules/list-view-grid/list-view-grid.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,22 +136,28 @@ describe('List View Grid Component', () => {
}));

it('should listen for the selectedColumnIdsChanged event and update the columns accordingly',
fakeAsync(() => {
(done) => {
setupTest();
flush();
tick(110); // wait for async heading
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();

component.grid.gridComponent.selectedColumnIdsChange.emit(['column1', 'column2']);
fixture.detectChanges();
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="column1"]')
).nativeElement.textContent.trim()).toBe('Column1');
expect(element.query(
By.css('th[sky-cmp-id="column2"]')
).nativeElement.textContent.trim()).toBe('Column2');
})
component.grid.selectedColumnIdsChange.subscribe((newColumnIds: string[]) => {
expect(newColumnIds).toEqual(['column1', 'column2']);
done();
});

component.grid.gridComponent.selectedColumnIdsChange.emit(['column1', 'column2']);
fixture.detectChanges();
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="column1"]')
).nativeElement.textContent.trim()).toBe('Column1');
expect(element.query(
By.css('th[sky-cmp-id="column2"]')
).nativeElement.textContent.trim()).toBe('Column2');
});
}
);

it('should listen for the sortFieldChange event', fakeAsync(() => {
Expand Down Expand Up @@ -430,7 +436,7 @@ describe('List View Grid Component', () => {
fixture.detectChanges();
}));

it('should handle grid columns changing', () => {
it('should handle grid columns changing to the same ids', () => {
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="name"]')).nativeElement.textContent.trim()
Expand All @@ -439,6 +445,8 @@ describe('List View Grid Component', () => {
By.css('th[sky-cmp-id="email"]')
).nativeElement.textContent.trim()).toBe('Email Initial');

spyOn(component.grid.selectedColumnIdsChange, 'emit').and.stub();

component.changeColumns();
fixture.detectChanges();
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
Expand All @@ -448,10 +456,35 @@ describe('List View Grid Component', () => {
expect(element.query(
By.css('th[sky-cmp-id="email"]')
).nativeElement.textContent.trim()).toBe('Email');
expect(component.grid.selectedColumnIdsChange.emit).not.toHaveBeenCalled();
});

it('should handle grid columns changing to contain a different id', (done) => {
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="name"]')).nativeElement.textContent.trim()
).toBe('Name Initial');
expect(element.query(
By.css('th[sky-cmp-id="email"]')
).nativeElement.textContent.trim()).toBe('Email Initial');

component.grid.selectedColumnIdsChange.subscribe((newColumnIds: string[]) => {
expect(newColumnIds).toEqual(['name', 'other']);
done();
});

component.changeColumnsNameAndOther();
fixture.detectChanges();
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="name"]')).nativeElement.textContent.trim()
).toBe('Name');
expect(element.query(
By.css('th[sky-cmp-id="other"]')).nativeElement.textContent.trim()
).toBe('Other');
});

it('should handle grid columns changing to completely different ids', () => {
it('should handle grid columns changing to contain only a different id', (done) => {
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(2);
expect(element.query(
By.css('th[sky-cmp-id="name"]')).nativeElement.textContent.trim()
Expand All @@ -460,13 +493,17 @@ describe('List View Grid Component', () => {
By.css('th[sky-cmp-id="email"]')
).nativeElement.textContent.trim()).toBe('Email Initial');

component.changeColumnsDifferent();
component.grid.selectedColumnIdsChange.subscribe((newColumnIds: string[]) => {
expect(newColumnIds).toEqual(['other']);
done();
});

component.changeColumnsOther();
fixture.detectChanges();
expect(element.queryAll(By.css('th.sky-grid-heading')).length).toBe(1);
expect(element.query(
By.css('th[sky-cmp-id="other"]')).nativeElement.textContent.trim()
).toBe('Other');

});
});

Expand Down
86 changes: 54 additions & 32 deletions src/modules/list-view-grid/list-view-grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
Input,
OnDestroy,
QueryList,
ViewChild
ViewChild,
EventEmitter,
Output
} from '@angular/core';

import { Observable } from 'rxjs/Observable';
Expand Down Expand Up @@ -60,7 +62,7 @@ import { ListViewDisplayedGridColumnsLoadAction } from './state/displayed-column
templateUrl: './list-view-grid.component.html',
providers: [
/* tslint:disable */
{ provide: ListViewComponent, useExisting: forwardRef(() => SkyListViewGridComponent)},
{ provide: ListViewComponent, useExisting: forwardRef(() => SkyListViewGridComponent) },
/* tslint:enable */
GridState,
GridStateDispatcher,
Expand Down Expand Up @@ -91,6 +93,9 @@ export class SkyListViewGridComponent
@Input()
public height: number | Observable<number>;

@Output()
public selectedColumnIdsChange = new EventEmitter<Array<string>>();

@ViewChild(SkyGridComponent)
public gridComponent: SkyGridComponent;

Expand All @@ -109,7 +114,7 @@ export class SkyListViewGridComponent
private searchFunction: (data: any, searchText: string) => boolean;
/* tslint:enable */

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

private ngUnsubscribe = new Subject();
Expand Down Expand Up @@ -210,15 +215,15 @@ export class SkyListViewGridComponent

public columnIdsChanged(selectedColumnIds: Array<string>) {
this.gridState.map(s => s.columns.items)
.take(1)
.subscribe(columns => {
let displayedColumns = selectedColumnIds.map(
columnId => columns.filter(c => c.id === columnId)[0]
);
this.gridDispatcher.next(
new ListViewDisplayedGridColumnsLoadAction(displayedColumns, true)
);
});
.take(1)
.subscribe(columns => {
let displayedColumns = selectedColumnIds.map(
columnId => columns.filter(c => c.id === columnId)[0]
);
this.gridDispatcher.next(
new ListViewDisplayedGridColumnsLoadAction(displayedColumns, true)
);
});
}

public sortFieldChanged(sortField: ListSortFieldSelectorModel) {
Expand Down Expand Up @@ -249,7 +254,7 @@ export class SkyListViewGridComponent
}

private handleColumnChange() {
// watch for changes in column components
// watch for changes in column components
this.columnComponents.changes
.takeUntil(this.ngUnsubscribe)
.subscribe((columnComponents) => {
Expand All @@ -276,19 +281,19 @@ export class SkyListViewGridComponent
previous value of items lastUpdate ensures that we only receive the latest items.
*/
return this.state.map((s) => {
return s.items;
return s.items;
})
.scan((previousValue: AsyncList<ListItemModel>, newValue: AsyncList<ListItemModel>) => {
if (previousValue.lastUpdate > newValue.lastUpdate) {
return previousValue;
} else {
return newValue;
}
})
.map((result: AsyncList<ListItemModel>) => {
return result.items;
})
.distinctUntilChanged();
.scan((previousValue: AsyncList<ListItemModel>, newValue: AsyncList<ListItemModel>) => {
if (previousValue.lastUpdate > newValue.lastUpdate) {
return previousValue;
} else {
return newValue;
}
})
.map((result: AsyncList<ListItemModel>) => {
return result.items;
})
.distinctUntilChanged();
}

private getSelectedIds(): Observable<Array<string>> {
Expand All @@ -301,18 +306,35 @@ export class SkyListViewGridComponent
.map(s => s.displayedColumns)
.scan(
(previousValue: AsyncList<SkyGridColumnModel>, newValue: AsyncList<SkyGridColumnModel>) => {
if (previousValue.lastUpdate > newValue.lastUpdate) {
return previousValue;
} else {
return newValue;
}
})
if (previousValue.lastUpdate > newValue.lastUpdate) {
return previousValue;
} else {
return newValue;
}
})
.map((result: AsyncList<SkyGridColumnModel>) => {
/* istanbul ignore next */
/* sanity check */
return result.items.map((column: SkyGridColumnModel) => {
return column.id || column.field;
});
}).distinctUntilChanged();
}).distinctUntilChanged((previousValue: string[], newValue: string[]) => {
return this.haveColumnIdsChanged(previousValue, newValue);
});
}

private haveColumnIdsChanged(previousValue: string[], newValue: string[]) {
if (previousValue.length !== newValue.length) {
this.selectedColumnIdsChange.emit(newValue);
return false;
}

for (let i = 0; i < previousValue.length; i++) {
if (previousValue[i] !== newValue[i]) {
this.selectedColumnIdsChange.emit(newValue);
return false;
}
}
return true;
}
}

0 comments on commit b84e1b8

Please sign in to comment.