Search code examples
angularangular9angular10

Why does ngOnChanges take time. Is it asynchronous?


I am using angular 9+ and i am little confused of the behavior of ngOnChanges life cycle.

What I am trying to do

I have a asynchrounous operation which sets a value (Object type) to the child component using @Input() decorator. The code is as below. (Stackblitz Here)

parent.ts

import { AfterViewInit, Component, VERSION, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  @ViewChild(ChildComponent) childComponent: ChildComponent;
  data = { value: null };

  constructor() {}

  ngAfterViewInit() {
    const foo = of([1])
      .pipe(delay(500))
      .subscribe(subscriber => {
        this.data = { value: 123 };
        this.childComponent.printState();
      });
  }
}

Parent.Html

<app-child [data]="data"></app-child>

Child Component

    import { Component, Input, OnChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnChanges {
  @Input() data = null;

  constructor() {}

  ngOnChanges(changes) {
    console.log('ngOnChanges');
  }

  printState() {
    console.log('printState');
    console.log(this.data.value);
  }
}

What i am trying to is , as soon as i change the value, i am trying to print the value of the set value by using a view child reference as shown above.

Ideally the sequence should have been

ngOnChanges // initial value
ngOnChanges // after value set
printState // after calling printState()

but i see

ngOnChanges 
printState 
ngOnChanges

in the console which is pretty consfusing. Why is ngOnChanges nor fired immediately. Why is it taking time. Can someone explain.

Thanks and stay safe :)


Solution

  • When you update any variable bound to @Input() as you are doing in ngAfterViewInit of AppComponent , the change detection will be scheduled by Angular to run just before view rendering and not immediately after assignment.

    Hence, the code in ngAfterViewInit will execute first, and code in ngOnChanges will be invoked by Angular in next tick.

    Yes, in summary, change detection is asynchronous.