angularcomponentsinteractionviewchildinputbinding

Angular Child Component is not being updated inmediatly


I'm learning Angular 6, I tought I was doing it right, but I'm facing a "problem-doubt"

I have a parent and a Child:

  1. My parent is sharing info to my child by using input binding
  2. A button trigger a function where the info is updated
  3. Inmediatly, parent calls a child function via @ViewChild

A Stackblitz can be found here

My parent components looks like:

Html:

This is the parent
<child [data]="my_data"></child>
<button (click)="fireAll()">Fire All!</button>

Typescript:

export class AppComponent  {
  @ViewChild(ChildComponent) childComp: ChildComponent;
  my_data = 'Nothing yet';

  public fireAll(){
    this.my_data = "I want to show this info in console";
    this.childComp.writeToConsole();
    //setTimeout(()=>this.childComp.writeToConsole(), 500); //This works well
  }

}

Child:

export class ChildComponent  {
  @Input() data: string;

  writeToConsole(){
    console.log(this.data);
  }
}

The problem is: The first time I click my button, I'm expecting to see in console "I want to show this info in console", instead of that I'm recieving "Nothing yet". But if I click it again, the expected result is reached. I suppose there is a delay between the parent pass data to child because if I use setTimeout to hold on a little, all works fine.

My questions:

  1. What is the best way to send data from parent to child and to use it inmediatly in child?
  2. What am I doing wrong?

Really appreciate your help, thanks


Solution

  • Actually everything is working fine. The thing your experiencing is the following.

    1. You hit the button
    2. You update my_data
    3. You call the child's writeToConsole method.
    4. At this moment the change detection is still evaluating all components
    5. The child hasn't been updated yet, so you still get old data
    6. Change detection is finished, new data is passed

    In your setup the console log will always be one step behind of what you expect. You call the method earlier than the change detection can do his job. The moment you introduce the delay (setTimeout) the change detection will be executed before you call the method. That's why it 'works' in your eyes.

    In all, everything is working fine. The parent should not call a method of the child. It should just provide the data to the child.

    If you want to use the new value as soon as possible you should implement OnChanges. It informs you when new data is coming into the component.

    ngOnChanges(): void {
      console.log('onChanges', this.data);
    }