I have an array that I use DoCheck and IterableDiffer to listen to changes in my code. When the array is changed, but when a property inside one of the objects in the array changes I don't get notified. I tried using KeyValueDiffer for each object in the array types
but it doesn't work in ngDoCheck
. Any ideas?
In the parent:
<comp [types]="types"></comp>
readonly: boolean = false;
types: {
readonly: boolean;
title: string;
value: any;
}[] = [{
title: 'title1',
readonly: this.readonly,
value: 1
}, {
title: 'title2',
readonly: this.readonly,
value: 2
}];
ngOnInit() {
setTimeout(() => {
this.readonly = true;
}, 5000)
}
In component comp
:
constructor(
private differsService: KeyValueDiffers
) {};
@Input types: any[] = [];
ngOnInit() {
this.differ = this.searchTypes.reduce((t, c, i) => {
t[`types_${i}`] = this.differsService.find(c).create();
return t;
}, {});
}
ngDoCheck(): void {
if (this.differ) {
Object.keys(this.differ).map((key: string) => {
const k = key.split('_');
const state = k.length === 1?this[k[0]]:this[k[0]][k[1]];
const changes = this.differ[key].diff(state);
if (changes) {
console.log(key, changes);
}
})
}
}
CodePudding user response:
In Angular, change detection is triggered on assignment. This means that you need to assign new value to bound variables or objects to trigger the change detection. So, instead of changing properties on objects only. Try to reassign the array again afterwards to trigger detection:
types = [...types];
Try assigning that in the parent component when updating the values in types array
<comp [types]="types"></comp>
This article might help you in understanding that concept: https://www.digitalocean.com/community/tutorials/angular-change-detection-strategy
CodePudding user response:
First point to be made is that this kind of change detection can be unnecessarily expensive and complicated. I'd recommend reading up on RxJS and how it works to handle changes in data.
In your specific example, however, the problem is not with your key differs, but with the logic of how you're handling readonly
In javascript, primitives (such as booleans) are not passed by reference, but by value.
This means that when you set the following:
readonly: this.readonly
the value in the type
for readonly is set to false, and that's it. If later you change this.readonly
the value within type
is not changed. If you want to keep the connection between the two "live", you need to pass by reference, with an object, for example. something like
this.readonly = { status: false }
Then when you do
this.readonly.status = true
that value will be changed in the types
as well.
Here's a stackblitz demonstrating it in action (and no need for keydiffers):
https://stackblitz.com/edit/angular-ivy-d8gige?file=src/app/app.component.ts