@@ -31,21 +31,12 @@ import {
31
31
} from '@angular/core' ;
32
32
import { CollectionViewer , DataSource } from './data-source' ;
33
33
import { CdkCellOutlet , CdkCellOutletRowContext , CdkHeaderRowDef , CdkRowDef } from './row' ;
34
- import { merge } from 'rxjs/observable/merge' ;
35
34
import { takeUntil } from 'rxjs/operator/takeUntil' ;
36
35
import { BehaviorSubject } from 'rxjs/BehaviorSubject' ;
37
36
import { Subscription } from 'rxjs/Subscription' ;
38
37
import { Subject } from 'rxjs/Subject' ;
39
38
import { CdkCellDef , CdkColumnDef , CdkHeaderCellDef } from './cell' ;
40
-
41
- /**
42
- * Returns an error to be thrown when attempting to find an unexisting column.
43
- * @param id Id whose lookup failed.
44
- * @docs -private
45
- */
46
- export function getTableUnknownColumnError ( id : string ) {
47
- return new Error ( `cdk-table: Could not find column with id "${ id } ".` ) ;
48
- }
39
+ import { getTableDuplicateColumnNameError , getTableUnknownColumnError } from './table-errors' ;
49
40
50
41
/**
51
42
* Provides a handle for the table to grab the view container's ng-container to insert data rows.
@@ -96,10 +87,7 @@ export class CdkTable<T> implements CollectionViewer {
96
87
/** Subscription that listens for the data provided by the data source. */
97
88
private _renderChangeSubscription : Subscription | null ;
98
89
99
- /**
100
- * Map of all the user's defined columns identified by name.
101
- * Contains the header and data-cell templates.
102
- */
90
+ /** Map of all the user's defined columns (header and data cell template) identified by name. */
103
91
private _columnDefinitionsByName = new Map < string , CdkColumnDef > ( ) ;
104
92
105
93
/** Differ used to find the changes in the data provided by the data source. */
@@ -123,15 +111,6 @@ export class CdkTable<T> implements CollectionViewer {
123
111
get trackBy ( ) : TrackByFunction < T > { return this . _trackByFn ; }
124
112
private _trackByFn : TrackByFunction < T > ;
125
113
126
- // TODO(andrewseguin): Remove max value as the end index
127
- // and instead calculate the view on init and scroll.
128
- /**
129
- * Stream containing the latest information on the range of rows being displayed on screen.
130
- * Can be used by the data source to as a heuristic of what data should be provided.
131
- */
132
- viewChange =
133
- new BehaviorSubject < { start : number , end : number } > ( { start : 0 , end : Number . MAX_VALUE } ) ;
134
-
135
114
/**
136
115
* Provides a stream containing the latest data array to render. Influenced by the table's
137
116
* stream of view window (what rows are currently on screen).
@@ -145,6 +124,15 @@ export class CdkTable<T> implements CollectionViewer {
145
124
}
146
125
private _dataSource : DataSource < T > ;
147
126
127
+ // TODO(andrewseguin): Remove max value as the end index
128
+ // and instead calculate the view on init and scroll.
129
+ /**
130
+ * Stream containing the latest information on what rows are being displayed on screen.
131
+ * Can be used by the data source to as a heuristic of what data should be provided.
132
+ */
133
+ viewChange =
134
+ new BehaviorSubject < { start : number , end : number } > ( { start : 0 , end : Number . MAX_VALUE } ) ;
135
+
148
136
// Placeholders within the table's template where the header and data rows will be inserted.
149
137
@ViewChild ( RowPlaceholder ) _rowPlaceholder : RowPlaceholder ;
150
138
@ViewChild ( HeaderRowPlaceholder ) _headerRowPlaceholder : HeaderRowPlaceholder ;
@@ -171,6 +159,24 @@ export class CdkTable<T> implements CollectionViewer {
171
159
}
172
160
}
173
161
162
+ ngOnInit ( ) {
163
+ // TODO(andrewseguin): Setup a listener for scrolling, emit the calculated view to viewChange
164
+ this . _dataDiffer = this . _differs . find ( [ ] ) . create ( this . _trackByFn ) ;
165
+ }
166
+
167
+ ngAfterContentInit ( ) {
168
+ this . _cacheColumnDefinitionsByName ( ) ;
169
+ this . _columnDefinitions . changes . subscribe ( ( ) => this . _cacheColumnDefinitionsByName ( ) ) ;
170
+ this . _renderHeaderRow ( ) ;
171
+ }
172
+
173
+ ngAfterContentChecked ( ) {
174
+ this . _renderUpdatedColumns ( ) ;
175
+ if ( this . dataSource && ! this . _renderChangeSubscription ) {
176
+ this . _observeRenderChanges ( ) ;
177
+ }
178
+ }
179
+
174
180
ngOnDestroy ( ) {
175
181
this . _rowPlaceholder . viewContainer . clear ( ) ;
176
182
this . _headerRowPlaceholder . viewContainer . clear ( ) ;
@@ -182,41 +188,38 @@ export class CdkTable<T> implements CollectionViewer {
182
188
}
183
189
}
184
190
185
- ngOnInit ( ) {
186
- // TODO(andrewseguin): Setup a listener for scroll events
187
- // and emit the calculated view to this.viewChange
188
- this . _dataDiffer = this . _differs . find ( [ ] ) . create ( this . _trackByFn ) ;
189
- }
190
191
191
- ngAfterContentInit ( ) {
192
- // TODO(andrewseguin): Throw an error if two columns share the same name
192
+ /** Update the map containing the content's column definitions. */
193
+ private _cacheColumnDefinitionsByName ( ) {
194
+ this . _columnDefinitionsByName . clear ( ) ;
193
195
this . _columnDefinitions . forEach ( columnDef => {
196
+ if ( this . _columnDefinitionsByName . has ( columnDef . name ) ) {
197
+ throw getTableDuplicateColumnNameError ( columnDef . name ) ;
198
+ }
194
199
this . _columnDefinitionsByName . set ( columnDef . name , columnDef ) ;
195
200
} ) ;
201
+ }
196
202
197
- // Re-render the rows if any of their columns change.
198
- // TODO(andrewseguin): Determine how to only re-render the rows that have their columns changed.
199
- const columnChangeEvents = this . _rowDefinitions . map ( rowDef => rowDef . columnsChange ) ;
200
-
201
- takeUntil . call ( merge ( ...columnChangeEvents ) , this . _onDestroy ) . subscribe ( ( ) => {
202
- // Reset the data to an empty array so that renderRowChanges will re-render all new rows.
203
- this . _rowPlaceholder . viewContainer . clear ( ) ;
204
- this . _dataDiffer . diff ( [ ] ) ;
205
- this . _renderRowChanges ( ) ;
203
+ /**
204
+ * Check if the header or rows have changed what columns they want to display. If there is a diff,
205
+ * then re-render that section.
206
+ */
207
+ private _renderUpdatedColumns ( ) {
208
+ // Re-render the rows when the row definition columns change.
209
+ this . _rowDefinitions . forEach ( rowDefinition => {
210
+ if ( ! ! rowDefinition . getColumnsDiff ( ) ) {
211
+ // Reset the data to an empty array so that renderRowChanges will re-render all new rows.
212
+ this . _dataDiffer . diff ( [ ] ) ;
213
+
214
+ this . _rowPlaceholder . viewContainer . clear ( ) ;
215
+ this . _renderRowChanges ( ) ;
216
+ }
206
217
} ) ;
207
218
208
- // Re-render the header row if the columns change
209
- takeUntil . call ( this . _headerDefinition . columnsChange , this . _onDestroy ) . subscribe ( ( ) => {
219
+ // Re-render the header row if there is a difference in its columns.
220
+ if ( this . _headerDefinition . getColumnsDiff ( ) ) {
210
221
this . _headerRowPlaceholder . viewContainer . clear ( ) ;
211
222
this . _renderHeaderRow ( ) ;
212
- } ) ;
213
-
214
- this . _renderHeaderRow ( ) ;
215
- }
216
-
217
- ngAfterContentChecked ( ) {
218
- if ( this . dataSource && ! this . _renderChangeSubscription ) {
219
- this . _observeRenderChanges ( ) ;
220
223
}
221
224
}
222
225
0 commit comments