Skip to content

Commit 33346e3

Browse files
committed
add tests
1 parent f2ceec9 commit 33346e3

File tree

5 files changed

+163
-113
lines changed

5 files changed

+163
-113
lines changed

src/cdk/table/table.spec.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {combineLatest} from 'rxjs/observable/combineLatest';
88
import {CdkTableModule} from './index';
99
import {map} from 'rxjs/operator/map';
1010

11-
fdescribe('CdkTable', () => {
11+
describe('CdkTable', () => {
1212
let fixture: ComponentFixture<SimpleCdkTableApp>;
1313

1414
let component: SimpleCdkTableApp;
@@ -108,14 +108,45 @@ fdescribe('CdkTable', () => {
108108
expect(fixture.nativeElement.querySelector('cdk-table').getAttribute('role')).toBe('treegrid');
109109
});
110110

111-
fit('should be able to dynamically add/remove column definitions', () => {
111+
it('should be able to dynamically add/remove column definitions', () => {
112112
const dynamicColumnDefFixture = TestBed.createComponent(DynamicColumnDefinitionsCdkTableApp);
113113
dynamicColumnDefFixture.detectChanges();
114+
dynamicColumnDefFixture.detectChanges();
114115

116+
const dynamicColumnDefTableEl = dynamicColumnDefFixture.nativeElement.querySelector('cdk-table');
115117
const dynamicColumnDefComp = dynamicColumnDefFixture.componentInstance;
116-
expect(dynamicColumnDefComp.dynamicColumns.push('columnA'));
117118

119+
// Add a new column and expect it to show up in the table
120+
let columnA = 'columnA';
121+
dynamicColumnDefComp.dynamicColumns.push(columnA);
122+
dynamicColumnDefFixture.detectChanges();
123+
expectTableToMatchContent(dynamicColumnDefTableEl, [
124+
[columnA], // Header row
125+
[columnA], // Data rows
126+
[columnA],
127+
[columnA],
128+
]);
129+
130+
// Add another new column and expect it to show up in the table
131+
let columnB = 'columnB';
132+
dynamicColumnDefComp.dynamicColumns.push(columnB);
118133
dynamicColumnDefFixture.detectChanges();
134+
expectTableToMatchContent(dynamicColumnDefTableEl, [
135+
[columnA, columnB], // Header row
136+
[columnA, columnB], // Data rows
137+
[columnA, columnB],
138+
[columnA, columnB],
139+
]);
140+
141+
// Remove column A expect only column B to be rendered
142+
dynamicColumnDefComp.dynamicColumns.shift();
143+
dynamicColumnDefFixture.detectChanges();
144+
expectTableToMatchContent(dynamicColumnDefTableEl, [
145+
[columnB], // Header row
146+
[columnB], // Data rows
147+
[columnB],
148+
[columnB],
149+
]);
119150
});
120151

121152
it('should re-render the rows when the data changes', () => {
@@ -602,8 +633,8 @@ class TrackByCdkTableApp {
602633
template: `
603634
<cdk-table [dataSource]="dataSource">
604635
<ng-container [cdkColumnDef]="column" *ngFor="let column of dynamicColumns">
605-
<cdk-header-cell *cdkHeaderCellDef> {{column}}</cdk-header-cell>
606-
<cdk-cell *cdkCellDef="let row"> {{column}}</cdk-cell>
636+
<cdk-header-cell *cdkHeaderCellDef> {{column}} </cdk-header-cell>
637+
<cdk-cell *cdkCellDef="let row"> {{column}} </cdk-cell>
607638
</ng-container>
608639
609640
<cdk-header-row *cdkHeaderRowDef="dynamicColumns"></cdk-header-row>
@@ -613,14 +644,9 @@ class TrackByCdkTableApp {
613644
})
614645
class DynamicColumnDefinitionsCdkTableApp {
615646
dynamicColumns: any[] = [];
616-
617647
dataSource: FakeDataSource = new FakeDataSource();
618648

619649
@ViewChild(CdkTable) table: CdkTable<TestData>;
620-
621-
addDynamicColumnDef() {
622-
this.dynamicColumns.push(this.dynamicColumns.length);
623-
}
624650
}
625651

626652
@Component({

src/cdk/table/table.ts

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,8 @@ export class CdkTable<T> implements CollectionViewer {
104104
/** Subscription that listens for the data provided by the data source. */
105105
private _renderChangeSubscription: Subscription | null;
106106

107-
/**
108-
* Map of all the user's defined columns identified by name.
109-
* Contains the header and data-cell templates.
110-
*/
111-
private _columnDefinitionsByName = new Map<string, CdkColumnDef>();
107+
/** Map of all the user's defined columns (header and data cell template) identified by name. */
108+
private _columnDefinitionsMap = new Map<string, CdkColumnDef>();
112109

113110
/** Differ used to find the changes in the data provided by the data source. */
114111
private _dataDiffer: IterableDiffer<T>;
@@ -131,15 +128,6 @@ export class CdkTable<T> implements CollectionViewer {
131128
get trackBy(): TrackByFunction<T> { return this._trackByFn; }
132129
private _trackByFn: TrackByFunction<T>;
133130

134-
// TODO(andrewseguin): Remove max value as the end index
135-
// and instead calculate the view on init and scroll.
136-
/**
137-
* Stream containing the latest information on the range of rows being displayed on screen.
138-
* Can be used by the data source to as a heuristic of what data should be provided.
139-
*/
140-
viewChange =
141-
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE});
142-
143131
/**
144132
* Provides a stream containing the latest data array to render. Influenced by the table's
145133
* stream of view window (what rows are currently on screen).
@@ -153,6 +141,15 @@ export class CdkTable<T> implements CollectionViewer {
153141
}
154142
private _dataSource: DataSource<T>;
155143

144+
// TODO(andrewseguin): Remove max value as the end index
145+
// and instead calculate the view on init and scroll.
146+
/**
147+
* Stream containing the latest information on what rows are being displayed on screen.
148+
* Can be used by the data source to as a heuristic of what data should be provided.
149+
*/
150+
viewChange =
151+
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE});
152+
156153
// Placeholders within the table's template where the header and data rows will be inserted.
157154
@ViewChild(RowPlaceholder) _rowPlaceholder: RowPlaceholder;
158155
@ViewChild(HeaderRowPlaceholder) _headerRowPlaceholder: HeaderRowPlaceholder;
@@ -185,13 +182,12 @@ export class CdkTable<T> implements CollectionViewer {
185182
}
186183

187184
ngAfterContentInit() {
188-
this._updateColumnDefinitions();
189-
this._columnDefinitions.changes.subscribe(() => this._updateColumnDefinitions());
185+
this._cacheColumnDefinitionsByName();
186+
this._columnDefinitions.changes.subscribe(() => this._cacheColumnDefinitionsByName());
190187
}
191188

192189
ngAfterContentChecked() {
193-
console.log('Content checked');
194-
this._updateColumnDefinitions();
190+
this._cacheColumnDefinitionsByName();
195191
}
196192

197193
ngAfterViewInit() {
@@ -224,14 +220,13 @@ export class CdkTable<T> implements CollectionViewer {
224220

225221

226222
/** Update the map containing the content's column definitions. */
227-
private _updateColumnDefinitions() {
228-
console.log('Updating columns');
229-
this._columnDefinitionsByName.clear();
223+
private _cacheColumnDefinitionsByName() {
224+
this._columnDefinitionsMap.clear();
230225
this._columnDefinitions.forEach(columnDef => {
231-
if (this._columnDefinitionsByName.has(columnDef.name)) {
226+
if (this._columnDefinitionsMap.has(columnDef.name)) {
232227
throw getTableDuplicateColumnNameError(columnDef.name);
233228
}
234-
this._columnDefinitionsByName.set(columnDef.name, columnDef);
229+
this._columnDefinitionsMap.set(columnDef.name, columnDef);
235230
});
236231
}
237232

@@ -388,7 +383,7 @@ export class CdkTable<T> implements CollectionViewer {
388383
private _getHeaderCellTemplatesForRow(headerDef: CdkHeaderRowDef): CdkHeaderCellDef[] {
389384
if (!headerDef.columns) { return []; }
390385
return headerDef.columns.map(columnId => {
391-
const column = this._columnDefinitionsByName.get(columnId);
386+
const column = this._columnDefinitionsMap.get(columnId);
392387

393388
if (!column) {
394389
throw getTableUnknownColumnError(columnId);
@@ -405,7 +400,7 @@ export class CdkTable<T> implements CollectionViewer {
405400
private _getCellTemplatesForRow(rowDef: CdkRowDef): CdkCellDef[] {
406401
if (!rowDef.columns) { return []; }
407402
return rowDef.columns.map(columnId => {
408-
const column = this._columnDefinitionsByName.get(columnId);
403+
const column = this._columnDefinitionsMap.get(columnId);
409404

410405
if (!column) {
411406
throw getTableUnknownColumnError(columnId);

src/demo-app/table/table-demo.html

Lines changed: 90 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@
1717
<md-radio-button [value]="'index'">Index</md-radio-button>
1818
</md-radio-group>
1919
</div>
20+
</div>
21+
22+
<md-card>
23+
<h3>
24+
CdkTable With Dynamic Column Def
25+
<div>
26+
<button md-raised-button
27+
(click)="addDynamicColumnDef()"
28+
[disabled]="dynamicColumnIds.length >= 4">
29+
Add Column Def
30+
</button>
31+
<button md-raised-button
32+
(click)="removeDynamicColumnDef()"
33+
[disabled]="dynamicColumnIds.length == 0">
34+
Remove Column Def
35+
</button>
36+
</div>
37+
</h3>
38+
39+
<cdk-table [dataSource]="dataSource">
40+
<ng-container [cdkColumnDef]="column.id" *ngFor="let column of dynamicColumnDefs">
41+
<cdk-header-cell *cdkHeaderCellDef> {{column.headerText}} </cdk-header-cell>
42+
<cdk-cell *cdkCellDef="let row"> {{row[column.property]}} </cdk-cell>
43+
</ng-container>
44+
45+
<cdk-header-row *cdkHeaderRowDef="dynamicColumnIds"></cdk-header-row>
46+
<cdk-row *cdkRowDef="let row; columns: dynamicColumnIds;"></cdk-row>
47+
</cdk-table>
48+
</md-card>
49+
50+
<md-card>
51+
<h3>CdkTable Example</h3>
2052

2153
<div class="demo-highlighter">
2254
Highlight:
@@ -26,85 +58,65 @@
2658
<md-checkbox (change)="toggleHighlight('odd', $event.checked)">Odd Rows</md-checkbox>
2759
</div>
2860

29-
<div>
30-
<button md-raised-button (click)="addDynamicColumnDef()" [disabled]="dynamicColumnIds.length >= 4">
31-
Add Dynamic Column Def
32-
</button>
33-
</div>
34-
</div>
61+
<cdk-table #table mdSort
62+
[dataSource]="dataSource"
63+
[trackBy]="userTrackBy">
64+
65+
<!-- Column Definition: ID -->
66+
<ng-container cdkColumnDef="userId">
67+
<cdk-header-cell *cdkHeaderCellDef
68+
md-sort-header arrowPosition="before">
69+
ID
70+
</cdk-header-cell>
71+
<cdk-cell *cdkCellDef="let row"> {{row.id}} </cdk-cell>
72+
</ng-container>
73+
74+
<!-- Column Definition: Progress -->
75+
<ng-container cdkColumnDef="progress">
76+
<cdk-header-cell *cdkHeaderCellDef
77+
md-sort-header start="desc">
78+
Progress
79+
</cdk-header-cell>
80+
<cdk-cell *cdkCellDef="let row">
81+
<div class="demo-progress-stat">{{row.progress}}%</div>
82+
<div class="demo-progress-indicator-container">
83+
<div class="demo-progress-indicator"
84+
[style.background]="row.progress > 50 ? 'green' : 'red'"
85+
[style.opacity]="getOpacity(row.progress)"
86+
[style.width.%]="row.progress"></div>
87+
</div>
88+
</cdk-cell>
89+
</ng-container>
90+
91+
<!-- Column Definition: Name -->
92+
<ng-container cdkColumnDef="userName">
93+
<cdk-header-cell *cdkHeaderCellDef md-sort-header>
94+
Name
95+
</cdk-header-cell>
96+
<cdk-cell *cdkCellDef="let row"> {{row.name}} </cdk-cell>
97+
</ng-container>
98+
99+
<!-- Column Definition: Color -->
100+
<ng-container cdkColumnDef="color">
101+
<cdk-header-cell *cdkHeaderCellDef
102+
md-sort-header disableClear>
103+
Color
104+
</cdk-header-cell>
105+
<cdk-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </cdk-cell>
106+
</ng-container>
35107

36-
<h3>CdkTable With Dynamic Column Def</h3>
37-
38-
<cdk-table [dataSource]="dataSource">
39-
<ng-container [cdkColumnDef]="column.id" *ngFor="let column of dynamicColumns">
40-
<cdk-header-cell *cdkHeaderCellDef> {{column.headerText}} </cdk-header-cell>
41-
<cdk-cell *cdkCellDef="let row"> {{row[column.property]}} </cdk-cell>
42-
</ng-container>
43-
44-
<cdk-header-row *cdkHeaderRowDef="dynamicColumnIds"></cdk-header-row>
45-
<cdk-row *cdkRowDef="let row; columns: dynamicColumnIds;"></cdk-row>
46-
</cdk-table>
47-
48-
<h3>CdkTable Example</h3>
49-
50-
<cdk-table #table mdSort
51-
[dataSource]="dataSource"
52-
[trackBy]="userTrackBy">
53-
54-
<!-- Column Definition: ID -->
55-
<ng-container cdkColumnDef="userId">
56-
<cdk-header-cell *cdkHeaderCellDef
57-
md-sort-header arrowPosition="before">
58-
ID
59-
</cdk-header-cell>
60-
<cdk-cell *cdkCellDef="let row"> {{row.id}} </cdk-cell>
61-
</ng-container>
62-
63-
<!-- Column Definition: Progress -->
64-
<ng-container cdkColumnDef="progress">
65-
<cdk-header-cell *cdkHeaderCellDef
66-
md-sort-header start="desc">
67-
Progress
68-
</cdk-header-cell>
69-
<cdk-cell *cdkCellDef="let row">
70-
<div class="demo-progress-stat">{{row.progress}}%</div>
71-
<div class="demo-progress-indicator-container">
72-
<div class="demo-progress-indicator"
73-
[style.background]="row.progress > 50 ? 'green' : 'red'"
74-
[style.opacity]="getOpacity(row.progress)"
75-
[style.width.%]="row.progress"></div>
76-
</div>
77-
</cdk-cell>
78-
</ng-container>
79-
80-
<!-- Column Definition: Name -->
81-
<ng-container cdkColumnDef="userName">
82-
<cdk-header-cell *cdkHeaderCellDef md-sort-header>
83-
Name
84-
</cdk-header-cell>
85-
<cdk-cell *cdkCellDef="let row"> {{row.name}} </cdk-cell>
86-
</ng-container>
87-
88-
<!-- Column Definition: Color -->
89-
<ng-container cdkColumnDef="color">
90-
<cdk-header-cell *cdkHeaderCellDef
91-
md-sort-header disableClear>
92-
Color
93-
</cdk-header-cell>
94-
<cdk-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </cdk-cell>
95-
</ng-container>
96-
97-
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
98-
<cdk-row *cdkRowDef="let row; columns: displayedColumns;
99-
let first = first; let last = last; let even = even; let odd = odd"
100-
[ngClass]="{
101-
'demo-row-highlight-first': highlights.has('first') && first,
102-
'demo-row-highlight-last': highlights.has('last') && last,
103-
'demo-row-highlight-even': highlights.has('even') && even,
104-
'demo-row-highlight-odd': highlights.has('odd') && odd
105-
}">
106-
</cdk-row>
107-
</cdk-table>
108+
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
109+
<cdk-row *cdkRowDef="let row; columns: displayedColumns;
110+
let first = first; let last = last; let even = even; let odd = odd"
111+
[ngClass]="{
112+
'demo-row-highlight-first': highlights.has('first') && first,
113+
'demo-row-highlight-last': highlights.has('last') && last,
114+
'demo-row-highlight-even': highlights.has('even') && even,
115+
'demo-row-highlight-odd': highlights.has('odd') && odd
116+
}">
117+
</cdk-row>
118+
</cdk-table>
119+
</md-card>
108120

109121
<h3>MdTable Example</h3>
110122

src/demo-app/table/table-demo.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
.demo-row-highlight-even { background: #ff0099; }
2323
.demo-row-highlight-odd { background: #83f52c; }
2424

25+
.mat-card {
26+
margin: 24px 0;
27+
max-height: 200px;
28+
overflow: auto;
29+
30+
h3 {
31+
display: flex;
32+
justify-content: space-between;
33+
align-items: center;
34+
}
35+
}
36+
2537
/** Styles so that the CDK Table columns have width and font size. */
2638
.cdk-table {
2739
font-size: 12px;

src/demo-app/table/table-demo.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ export class TableDemo {
5151
this.dynamicColumnIds = this.dynamicColumnDefs.map(columnDef => columnDef.id);
5252
}
5353

54+
removeDynamicColumnDef() {
55+
this.dynamicColumnDefs.pop();
56+
this.dynamicColumnIds.pop();
57+
}
58+
5459
connect() {
5560
this.displayedColumns = ['userId', 'userName', 'progress', 'color'];
5661
this.dataSource = new PersonDataSource(this._peopleDatabase,

0 commit comments

Comments
 (0)