8

I have a child component that contains complex input (some chart data). I am sending this chart data from the parent component through the @Input() decorator in Angular 5 after getting API response. So, I need to sync the chart according with the API response every time it gets changed on the parent component, hence, the OnChange Lifecyle. But unfortunately, I am not able to get this to work properly. I tried with setting a dummy input field with basic number type and increment it but in vain. Here's my implementation:

Child chart component:

export class ChartComponent implements OnInit, OnChanges {

  @Input() chartData;
  @Input() triggerChart;

  ngOnChanges(changes: SimpleChanges) {
    console.log(changes);
  }

}

Parent component html:

<app-chart [chartData]="chartData" [triggerChart]="triggerChartData"></app-chart>
<input [(ngModel)]="triggerChartData" type="hidden">

Parent component:

this.chartService.getChartData(params).subscribe(res => {
  this.chartData = res;
  this.triggerChartData++;
});

PS: The ngOnChanges as the title indicates only fires once when the component initializes with undefined values.

Mehdi Benmoha
  • 3,694
  • 3
  • 23
  • 43
  • Are you sure that your ChartData is resolving in the Parent component? – joshrathke Jan 15 '18 at 14:17
  • Yes, I am able to log the API response to the console. However, I noticed that the triggerChartData doesn't increment. It logs NaN – Mehdi Benmoha Jan 15 '18 at 14:21
  • Try logging out the Input properties to your DOM instead using handlebars. {{ chartData | json }} within the child component. Objects are tough on change detection, because an Input will only pass the object as Reference, meaning change detection won't detect changes beyond the initial reference to the object within the parent component being defined. – joshrathke Jan 15 '18 at 14:26
  • 1
    In terms of the triggerChartData++ rendering NaN, trying initializing the property with a Number value: `triggerChartData: number = 0`. Then using `++` should work. – joshrathke Jan 15 '18 at 14:30
  • 1
    Read this https://stackoverflow.com/questions/38571812/how-to-detect-when-an-input-value-changes-in-angular - Especially the edit "EDIT 2017-07-25:..." – Hoang Duc Nguyen Jan 15 '18 at 14:32
  • @HoangDucNguyen Thanks !!! I used the ChangeDetectorRef and it worked !!! May you make an answer for this for future guys? Or should I auto-answer with the working code ? – Mehdi Benmoha Jan 15 '18 at 14:49

2 Answers2

12

Thanks to @HoangDucNguyen, here's the working code:

this.chartService.getChartData(params).subscribe(res => {
  this.chartData = res;
  this.changeDetectorRef.detectChanges();
});

Of course you will need to import the ChangeDetectorRef class from @angular/core and inject it in your constructor.

Explanation:
When variables are changed outside of the angular context (in here: it's the rxJs context), Angular isn't able to detect changes on the variables. So, you need to manually fire the detect changes angular method.

Official doc: https://angular.io/api/core/ChangeDetectorRef

Mehdi Benmoha
  • 3,694
  • 3
  • 23
  • 43
0

you must use changeDetectorRef

this.cd.markForCheck();
if (!this.cd['destroyed']) {
    this.cd.detectChanges();
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
zinderud
  • 27
  • 2