0

There are two components namely ParentComponent and ChildComponent. We are binding a variable from parent component to child component. As per angular documentation "ngOnChanges" of child component gets called whenever the value of property in parent component get changed. Now in ParentComponent we are changing the value of that variable for the two times but in ChildComponent , "ngOnChanges" is getting called only one time.

Parent Component is as follows:

ParentComponent.html

<p>parentcomponent works!</p>
<button (click)="onClicking()">Click here</button>
<app-childcomponent [temp]="inputfromparent"></app-childcomponent>

ParentComponent.ts

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

@Component({
  selector: 'app-parentcomponent',
  templateUrl: './parentcomponent.component.html',
  styleUrls: ['./parentcomponent.component.css']
})
export class ParentcomponentComponent implements OnInit {

  private inputfromparent = "B"
  constructor() { }

  ngOnInit() {
  }

  onClicking(){
    this.inputfromparent = "C"; //line1
    console.log("Hello");
    this.inputfromparent= "D"; //line2
  }
}

Child Component is as follows:

ChildComponent.ts

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

@Component({
  selector: 'app-childcomponent',
  templateUrl: './childcomponent.component.html',
  styleUrls: ['./childcomponent.component.css']
})
export class ChildcomponentComponent implements OnInit, OnChanges{

  @Input() private temp = "A";
  constructor() { }

  ngOnInit() {
  }

  ngOnChanges(change){
    var test = change;
    console.log(test);
    console.log(this.temp);
  }
}

In ParentComponent.ts file we are changing the value of "inputfromparent " two times whenever "onClicking" method gets called on clicking button defined in ParentComponent.html file (refer line1 and line2). And since we are binding this variable with variable "temp" of ChildComponent.ts file, so "ngOnChanges" of ChildComponent.ts file should get called twice as per angular documentation, which is as follows:

A lifecycle hook that is called when any data-bound property of a directive changes. Define an ngOnChanges() method to handle the changes.

But "ngOnChanges" of ChildComponent.ts file is only getting called only one time whenever "onClicking" is called on clicking button defined in ParentComponent.html file.

My doubt is that, since we are changing the value of "inputfromparent", two times in "onClicking" method of ParentComponent.ts file, so "ngOnChanges" of ChildComponent.ts file should get called for the two times. But it is getting called only once.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
kushagra
  • 57
  • 2
  • 11

2 Answers2

1
  onClicking() {
    this.inputfromparent = "C"; //line1
    console.log("Hello");
    this.inputfromparent= "D"; //line2
  }

This runs synchronously. That is, no other code is executed until onClicking ends its run: for the entire outside world (template engine, change detection, etc.), onClicking() was called, before it, the value of inputfromparent was "B", and after, it was "D". What's between is pretty much a black box.

mbojko
  • 13,503
  • 1
  • 16
  • 26
  • But at line1 we are changing the value of "inputfromparent" from "B" to "C". Hence change detection cycle should have also run "ngOnChanges" of ChildComponent.ts file at this time also. So why it doesn't get called at this time (when value of "inputfromparent" is updated to "C")? – kushagra Oct 02 '19 at 09:22
  • The change detection doesn't run between line 1 and 2, because _nothing_ runs between line 1 and 2 except for the `console.log`. – mbojko Oct 02 '19 at 09:26
  • Thank you for this explanation. But could you please explain why change detection can't run between line 1 and 2, although we are changing the value of property in parent component and hence according to angular documentation, change detector should run? – kushagra Oct 02 '19 at 09:30
  • Try reading this https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html for starters. – mbojko Oct 02 '19 at 09:33
0

You should call the changedetector otherwise you'll get exception from angular. pls check console.

export class ParentcomponentComponent implements OnInit {

  private inputfromparent = "B";
  constructor(private cd: ChangeDetectorRef) { }

  ngOnInit() {
  }

  onClicking(){
    this.inputfromparent = "C"; //line1
    this.cd.detectChanges();
    console.log("Hello");
    this.inputfromparent= "D"; //line2
    this.cd.detectChanges();
  }
}

Some thoughts: inputfromparent should be public to avoid production build with AOT The ChildComponent should use OnPush changedetection.

tano
  • 2,657
  • 1
  • 15
  • 16
  • Why we need to call "detectChanges()" explicitly when angular calls it for us whenever it detects any changes in property in Parent Component? Please read my doubt again and try to clear it. – kushagra Oct 02 '19 at 09:28
  • If you change its value the changedetector will do its job and after that checks its value again just to be sure and if it has changed throws an exception similar to this: ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: C'. Current value: 'ngIf: D'. I assume that you can see it on your console. – tano Oct 02 '19 at 09:32