-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(data-table): re-render when columns change #4830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(data-table): re-render when columns change #4830
Conversation
// Remove column_a and swap column_b/column_c. | ||
component.columnsToRender = ['column_c', 'column_b']; | ||
fixture.detectChanges(); | ||
fixture.detectChanges(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need two detectChanges? Add a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, looks like whatever was needing it before is gone. Just need one now
/** | ||
* Stream containing the latest information on what rows are being displayed on screen. | ||
* Can be used by the data source to as a heuristic of what data should be provided. | ||
*/ | ||
viewChanged = | ||
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE}); | ||
|
||
/** Stream that emits when a row def has a change to its array of columns to render. */ | ||
columnsChange = new Observable<void[]>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name should probably be consistent w/ viewChanged
; maybe change viewChanged
to just viewChange
?
@@ -112,21 +116,32 @@ export class CdkTable implements CollectionViewer { | |||
this._columnDefinitions.forEach(columnDef => { | |||
this._columnDefinitionsByName.set(columnDef.name, columnDef); | |||
}); | |||
|
|||
// Get and merge the streams for column changes made to the row defs | |||
const rowDefs = this._rowDefinitions.toArray().concat(this._headerDefinition); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expert mode:
const rowDefs = [...this._rowDefinitions.toArray(), this._headerDefinition];
this.dataSource.connect(this).subscribe((rowsData: any[]) => { | ||
const streams = [this.dataSource.connect(this), this.columnsChange]; | ||
Observable.combineLatest(streams).subscribe((result: any[]) => { | ||
console.log('Rendering all rows'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
console.log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can pretend this didn't make it through to review
// TODO(andrewseguin): If the data source is not | ||
// present after view init, connect it when it is defined. | ||
// TODO(andrewseguin): Unsubscribe from this on destroy. | ||
this.dataSource.connect(this).subscribe((rowsData: any[]) => { | ||
const streams = [this.dataSource.connect(this), this.columnsChange]; | ||
Observable.combineLatest(streams).subscribe((result: any[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be more specific than any
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it can be since I cannot type the individual elements of the array.
// TODO(andrewseguin): If the data source is not | ||
// present after view init, connect it when it is defined. | ||
// TODO(andrewseguin): Unsubscribe from this on destroy. | ||
this.dataSource.connect(this).subscribe((rowsData: any[]) => { | ||
const streams = [this.dataSource.connect(this), this.columnsChange]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More specific name than streams
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going with renderChange
in that it causes render changes? Naming is hard
3d9a7a3
to
8327ecd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion for future/best practice, otherwise, LGTM
toggleColorColumn() { | ||
let colorColumnIndex = this.propertiesToDisplay.findIndex((col: string) => col === 'color'); | ||
if (colorColumnIndex == -1) { | ||
this.propertiesToDisplay.push('color'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly later, but I'm always cautious about passing strings around because I'm great at mistyping them. Perhaps a best practice would be to define a columns type for the demo:
type columns = 'color'|'progress'; // etc.
And then we'll have a little bit of type safety with the propertiesToDisplay. It would also make us less likely to hit the no column definition error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that sounds good, I'll add that in.
|
||
let initialTableContent = [['Column A', 'Column B', 'Column C']]; | ||
dataSource.data.forEach(rowData => initialTableContent.push([rowData.a, rowData.b, rowData.c])); | ||
expect(tableElement).toMatchTableContent(initialTableContent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You typically want to avoid having logic in unit tests like this, instead preferring to hard-code the values. I think this all should be
expect(tableElement).toMatchTableContent([
['Column A', 'Column B', 'Column C'],
[data[0].a, data[0].b, data[0].c],
[data[1].a, data[1].b, data[2].c],
[data[2].a, data[2].b, data[1].c],
]);
Which is also much easier to visually see what's going on with the test
// TODO(andrewseguin): If the data source is not | ||
// present after view init, connect it when it is defined. | ||
// TODO(andrewseguin): Unsubscribe from this on destroy. | ||
this.dataSource.connect(this).subscribe((rowsData: any[]) => { | ||
const renderChange = [this.dataSource.connect(this), this.columnsChange]; | ||
Observable.combineLatest(renderChange).subscribe(([data]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you destructuring the function arguments here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only part of the observable we want is the first element in the array result, so just grabbing it here. If it looks too odd I can change it back to (result: any[]) and then grab result[0] for our data.
new BehaviorSubject<{start: number, end: number}>({start: 0, end: Number.MAX_VALUE}); | ||
|
||
/** Stream that emits when a row def has a change to its array of columns to render. */ | ||
columnsChange = new Observable<void[]>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void[]
doesn't make sense- it's "array of nothings". It should either be just void
or capture whatever argument is being emitted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree but it makes Typescript happy. The merged streams are each Observable and combined make up Observable<void[]>
2ceeb69
to
1904c26
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
2ed6b9c
to
ac23efa
Compare
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
No description provided.