0

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

WindSaber
  • 323
  • 1
  • 3
  • 15
  • It works for me in Chrome. See [this stackblitz](https://stackblitz.com/edit/angular-problem-databinding-svyhec). – ConnorsFan Sep 21 '18 at 16:40
  • 1
    @ConnorsFan , coud you please attend to console? First time button is clicked appears "Nothing yet".....after second time is different – WindSaber Sep 21 '18 at 16:42
  • 1
    You are right. If you call `ChangeDetectorRef.detectChanges()` after setting the value, then it works. See [the stackblitz](https://stackblitz.com/edit/angular-problem-databinding-svyhec). – ConnorsFan Sep 21 '18 at 16:46
  • @ConnorsFan thanks for quickly response. But using detectChanges wouldn't be bad for performance? – WindSaber Sep 21 '18 at 16:48
  • 1
    An alternative is to set the value inside of the child component method that you call in the button event handler. – ConnorsFan Sep 21 '18 at 16:50
  • Good alternative, thanks @ConnorsFan – WindSaber Sep 21 '18 at 16:51

2 Answers2

3

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);
}
Ruben Vermeulen
  • 411
  • 2
  • 8
0

I've updated your stackblitz. On first click, I have 'I want to show this info in console' printing to the console first.

Example Stackblitz

Flignats
  • 1,234
  • 10
  • 21
  • Thanks, but what I'm really expecting is not to write at console at any component instead, I want that my ChildComponent writes recent changed value – WindSaber Sep 21 '18 at 16:54
  • [Updated Stackblitz](https://stackblitz.com/edit/angular-problem-databinding-m4sdjp?file=src%2Fapp%2Fapp.component.ts) - this? – Flignats Sep 21 '18 at 17:00
  • is a good another way....Although in that case input binding wouln't be neccesary....thanks – WindSaber Sep 21 '18 at 17:04
  • I think, ideally, the dumb component wouldn't contain logic like writing to the console. Instead, the child component should emit an event to the parent component that handles said logic. But, you may have a situation that dictates otherwise. – Flignats Sep 21 '18 at 17:21