Mr. Mars
Mr. Mars

Reputation: 840

ngOnChanges is not called but the view is updated correctly

I have a question related to the following code:

Child

export class ChildComponent implements OnChanges {
    public @Input() data: string[];

    ngOnChanges(changes: SimpleChanges) {
        console.log('I am here');
    }
}

Child Template

{{ data | json }} // This is not necessary. The behaviour is the same with or without it.

<div *ngFor="let item of data">
    {{ item }}
</div>

Parent

export class AppComponent implements OnInit {
    public test: string[] = ['hello'];

    ngOnInit() {
        console.log('I am here');
    }

    public addItem() {
        this.test.push('sample');
    }
}

Parent Template

<child-component [data]="test"></child-component>
<button (click)="addItem()">Add</button>

I understand that ngOnChanges will only be called when the array reference changes and if I push an element to the array it will not be called. The following catches my attention. When I press the add button, a new element is added to the array and the view is updated correctly. I use the json pipe and an ngFor to prove that it updates correctly. If I not use json pipe, behaviour is the same. So, if the view is updated correctly, why isn't ngOnChanges called? Who is responsible for detecting that there is a change to show it in the view?

In summary, the doubt is as follows. Why when an element is added to the array the view is updated correctly but why is ngOnChanges not called?

Change detection is done differently?

Upvotes: 0

Views: 683

Answers (1)

Eatos
Eatos

Reputation: 464

As You might be well aware ngOnChanges is designed for handling any changes in @Input() properties (in case that the simple feed of the new data to the component might have some additional effects and cannot be done by combining set and @Input()). So it is focused only on @Input() changes. Also as You well aware this will update only if the reference is about to change.

And Your component gets updated anyway because:

  • You are not telling the component to use only OnPush change detection strategy (so it will change not only on those reference changes of any @Input() or on any observable/event)
  • and in addition (which is a key here) You have a inpure pipe inside Your child view. Here I found some question about dirty pipes and I think it should answer You question: link (as json pipe is inpure - docs). Try to delete it and see what will happen.

Please kindly accept the fact this is just a theory. But I am quite sure that it is a right one.

Edit: oh, and it seems like there is a perfect example of that in official docs here:

...the flying heroes display updates as you add heroes, even when you mutate the heroes array.

Upvotes: 2

Related Questions