Reputation: 311
I got a component hierarchy that looks a bit like this:
@Component({
...
})
export class A {
constructor(private _serviceThatDeliversData: Service){}
getData(): Array<DataItem> {
return this._serviceThatDeliversData.getData();
}
}
html:
<b-selector [data]="getData()"></b-selector>
Child component:
@Component({
selector: 'b-selector'
...
})
export class B {
@Input() data: Array<DataItem>;
}
html:
<ul>
<li *ngFor="let item of data">
<c-selector [item]="item"></c-selector>
</li>
</ul>
So I got a parent component 'A' that receives data from a service. The serviceThatDeliversData creates the DataItem list every time it receives data from a websocket. This list is then passed down to 'B' where every list entry is used as a base for sub components ('C', I omitted the C component here cause it basically just presents the input data 'item').
My problem now is the following: Since the list changes every time the service gets an update, the whole list of C components + the B component is newly created. I assume because the DataItem list changes completely Angular notices them as new entries (?) and the list as a new one itself (?) However in reality it might very well be that only one item was added or removed or just a field has changed in one of the items. So only one C component would needed to be removed/added/updated.
Since that is the case any animations happening in the view in any of the C components stop and start again once the list is recreated. That plus some other side effects I would like to avoid.
So my question is, is there a way to let Angular only update the C components which relate to a DataItem that actually changed internally AND the ones that were added or removed to/from the list, but leave the ones that have not changed untouched?
I have searched for a while and found that one could use changeDetection: ChangeDetectionStrategy.OnPush, however I have not found a working example (with a changing array and changing array elements (internally)) that would help me with my problem.
I assume one could store a copy of the list in 'B', check the changes manually and then react to them - which could also be done with an animation to signal the user which entry was removed or added - however that would require a way to stop Angular from updating (recreating) 'B' and the 'C' components at all. I take it using the same array (clearing it and repopulating it with the new entries) might work.
But I'd still like to know if this could be possible via raw Angular mechanisms.
Upvotes: 0
Views: 3183
Reputation: 14257
The changedetection strategy OnPush
only picks up changes to values decorated with the Input
-decorator and only if the reference of the value changes.
For example myArray[1] = 'a';
only mutates the array and no new reference is created, therefore angular with OnPush
strategy wouldn't pick up the change. You have to clone the array and make the change to create a new array reference.
Your problem with angular recreating the elements inside an ngForOf
directive is descriped in another answer of me. Read the note at the end of the answer.
Upvotes: 1