Angular ngOnChanges in child doesn't trigger after subscribe manipulates data

746 Views Asked by At

I have a problem with ngOnChanges not being fired for a child component after data is being manipulated in parent via subscribe method.

Basically my main component looks like this:

public imageGroups: IImageGroup[];
public status$: Observable<ModelStatusesModel>;


public ngOnChanges(changes: SimpleChanges): void {
  if (Boolean(this.treeData)) {
    this.imageGroups = this.treeDataService.convertImageGroups(this.treeData);
    this.status$ = this.updateStatus();
    this.status$.subscribe((status: ModelStatusesModel) => {
      this.treeDataService.updateStatus(this.imageGroups, status); // this function makes changes to this.imageGroups
      console.log('subscribe happened');
    });
  }
}

HTML:

...
<ul class="treeview-nodes-wrapper">
  <treeview-branch *ngFor="let group of (imageGroups)"
                                          [group]="group"></treeview-branch>
</ul>
...

The branch has also ngOnChnages:

public ngOnChanges(): void {
  this._currentNodeDisabled = this.group.isDisabled;
  console.log(this.group); //returns isDisables as true
  console.log(this.group.isDisabled); //returns false
  console.log(this._currentNodeDisabled); //returns false
}

When I run my application this is the result in the console:

{ ... isDisabled: true ...},
false
false
subscribe happened

I was also trying to surround the call inside my subscription in a ngZone.run but without any success. Do you have any idea how to tell angular that ngOnChanges in the child triggered?

EDIT: What works for me is creating a property in the parent component (public change = false;) then toggling this property inside my subscribe method and giving it as an input to my children elements. That gets picked up as a change. Even though this solves my problem, it looks more like a very hacky way of writing the code.

2

There are 2 best solutions below

0
On

This is a result of ngOnChanges being triggered when an input value changes, and with objects that are passed by reference the modification of their properties does not explicitly change the thing being passed down. The solution is often times to do a clone, ...spread operator, or reassign to the property that is being passed down in the parent's [input].

Your solution of having an additional input that changes to a new value to trigger ngOnChanges works as well, it's a bit of a workaround but that's web dev. just remember if you set the property to true then true again it won't trigger, so a count variable may work better (it's kinda hacky).

0
On

Doing a clone via JSON.parse solved my problem in a cleaner way than toggling a variable :

...
  this.status$.subscribe((status: ModelStatusesModel) => {
    this.treeDataService.updateStatus(this.imageGroups, status);
    triggerChange();
  });
...

private triggerChange() {
    this.imageGroups = JSON.parse(JSON.stringify(this.imageGroups));
}