I have a data table component ( angular2-data-table ) project where we changed the project from Angular's traditional change detection to OnPush
for optimized rendering speeds.
Once the new change detection strategy was implemented, a bug was filed referencing the table is not updating when the data object is mutated such as object's property updates Reference: https://github.com/swimlane/angular2-data-table/issues/255. A strong use case can be made for this type of need for things such as inline editing or external data changes to a single property in a large data collection like a stock ticker.
In an effort to resolve the issue, we added a custom trackBy property checker called trackByProp
. Reference: commit. Unfortunately, this solution did not resolve the matter.
On the demo page under live reloading you can see the demo referenced in the above commit running but not updating the table until you click thus triggering change detection.
The structure of the component is something like:
Table > Body > Row Group > Row > Cell
all of these components implementOnPush
. I'm using getters/setters in the row setter to trigger page recalculations like shown here.
We'd like to stay with the OnPush
change detection for those implementing this pattern, however, as a open-source project with multiple consumers one could argue some sort of custom checking function for the visible row values on the screen.
All that said, trackBy
is not triggering change detection in row cell values, what is the best way to accomplish this?
Angular2 change detection doesn't check the contents of arrays or object.
A hacky workaround is to just create a copy of the array after mutation
this.myArray.push(newItem);
this.myArray = this.myArray.slice();
This way this.myArray
refers a different array instance and Angular will recognize the change.
Another approach is to use an IterableDiffer
(for arrays) or KeyValueDiffer
(for objects)
// inject a differ implementation
constructor(differs: KeyValueDiffers) {
// store the initial value to compare with
this.differ = differs.find({}).create(null);
}
@Input() data: any;
ngDoCheck() {
var changes = this.differ.diff(this.data); // check for changes
if (changes && this.initialized) {
// do something if changes were found
}
}