Skip to content

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

Merged
merged 9 commits into from
Jun 7, 2017

Conversation

andrewseguin
Copy link
Contributor

No description provided.

@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label May 26, 2017
// Remove column_a and swap column_b/column_c.
component.columnsToRender = ['column_c', 'column_b'];
fixture.detectChanges();
fixture.detectChanges();

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?

Copy link
Contributor Author

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[]>();
Copy link
Member

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);
Copy link
Member

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');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.log

Copy link
Contributor Author

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[]) => {
Copy link
Member

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?

Copy link
Contributor Author

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];
Copy link
Member

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?

Copy link
Contributor Author

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

@andrewseguin andrewseguin force-pushed the table-dynamic-columns branch from 3d9a7a3 to 8327ecd Compare May 30, 2017 17:32
Copy link

@ErinCoughlan ErinCoughlan left a 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');

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.

Copy link
Contributor Author

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);
Copy link
Member

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]) => {
Copy link
Member

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?

Copy link
Contributor Author

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[]>();
Copy link
Member

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

Copy link
Contributor Author

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[]>

@andrewseguin andrewseguin force-pushed the table-dynamic-columns branch from 2ceeb69 to 1904c26 Compare June 1, 2017 22:08
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jelbourn jelbourn added pr: lgtm action: merge The PR is ready for merge by the caretaker and removed pr: needs review labels Jun 5, 2017
@andrewseguin andrewseguin force-pushed the table-dynamic-columns branch from 2ed6b9c to ac23efa Compare June 6, 2017 18:36
@andrewseguin andrewseguin merged commit e81619b into angular:master Jun 7, 2017
@andrewseguin andrewseguin deleted the table-dynamic-columns branch November 28, 2017 20:35
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants