Home > Software engineering >  angular10: How to detect complex input object in array change
angular10: How to detect complex input object in array change

Time:09-03

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

  • Related