Components: [Table] Dynamic columns defined by array of objects break change detection

Created on 20 Nov 2018  路  4Comments  路  Source: angular/components

Bug, feature request, or proposal: Bug

What is the expected behavior?

Dynamic columns defined by an array of objects should behave the same as dynamic columns defined by an array of strings when the contents of the array are modified.

What is the current behavior?

When the array of objects which defines the column definition changes, the row data is no longer updated by external actions.

What are the steps to reproduce?

Stackblitz showing behaviour with array of strings: https://stackblitz.com/edit/angular-imgoju-nwwp7d?file=app%2Ftable-dynamic-columns-example.ts
Stackblitz showing behaviour with array of objects: https://stackblitz.com/edit/angular-imgoju?file=app%2Ftable-dynamic-columns-example.ts

In both stackblitz links, the Toggle Modifier button adds an 'M' to all of the data in the table. The Rebuild Columns button rebuilds the column definitions.

Note that in the example using an array of object to define the columns, the Toggle Modifier button no longer updates the table values once the Rebuild Columns button has been clicked.

What is the use-case or motivation for changing an existing behavior?

In certain cases, more complex column definition objects will be required. In these cases, the column definitions cannot properly be updated dynamically.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

"@angular/core": "7.0.4",
"@angular/material": "7.0.4",

Is there anything else we should know?

Most helpful comment

This is actually occuring because the array of strings does not cause the *ngFor to stamp out new ng-containers because Angular is able to track the values in the list of strings because they pass === checks. Since === is false for the checks in the array of objects, new ng-containers are stamped out for each of the columns. Because the old ng-container instances are removed and new ones put in its place without table knowing about it. The old instances are left in the tables view container and the new ones are unused. Since the new (current) ones are not in the tables view container and are not inserted in the DOM, Angular does not update them, not does the table remove the old instances.

To remedy this, you will just need to use a trackBy method in your *ngFor definition to be sure to reuse the ng-containers. You can see a working fork of your stackblitz here

All 4 comments

This is actually occuring because the array of strings does not cause the *ngFor to stamp out new ng-containers because Angular is able to track the values in the list of strings because they pass === checks. Since === is false for the checks in the array of objects, new ng-containers are stamped out for each of the columns. Because the old ng-container instances are removed and new ones put in its place without table knowing about it. The old instances are left in the tables view container and the new ones are unused. Since the new (current) ones are not in the tables view container and are not inserted in the DOM, Angular does not update them, not does the table remove the old instances.

To remedy this, you will just need to use a trackBy method in your *ngFor definition to be sure to reuse the ng-containers. You can see a working fork of your stackblitz here

@josephperrott That makes a lot of sense, thanks!

it make my app working!!! thank you so much 鉂わ笍

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._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shlomiassaf picture shlomiassaf  路  3Comments

Miiekeee picture Miiekeee  路  3Comments

julianobrasil picture julianobrasil  路  3Comments

constantinlucian picture constantinlucian  路  3Comments

xtianus79 picture xtianus79  路  3Comments