Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpressionChangedAfterItHasBeenCheckedError in child component

Tags:

angular

I have a parent Component which updates a every second its array myValue. In a child component I want to create a chart which uses this array as data and updates also every time the parent updates.

When I run this application I get this error:

Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'hidden: true'. Current value: 'hidden: false'.

Here is my parent component:

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements AfterContentInit, OnDestroy {

    private myValues: MyValue[];
    private alive: boolean;

    constructor(private valueService: ValueService) {
    this.alive = true;
    this.myValues = [];
  }

  ngAfterContentInit(): void {
    TimerObservable.create(0, 1000)
      .takeWhile(() => this.alive)
      .subscribe(() => {
        this.valueService.doSmth().subscribe(
          value => {
            this.myValues.push(value);
          }
        );
      });
  }
...

}

The parent template looks like this:

<ul>
  <li *ngFor="let value of myValues">
    <p>{{value.name}}</p>
  </li>
</ul>

<app-value-chart [chartData] = myValues></app-value-chart>

And here is my child component:

@Component({
  selector: 'app-value-chart',
  templateUrl: './value-chart.component.html',
  styleUrls: ['./value-chart.component.scss']
)}
export class ValueChartComponent implements AfterViewInit {
  @Input() chartData: MyValue[];

  chart: any;

  ngAfterViewInit(): void {
    this.createChart(); // creates chart with ChartJS
    const tmp: number[] = [];
    for (let i = 0; i < this.chartData.length; i++) {
      tmp.push(this.chartData[i].x);
    }
    this.chart.data.datasets[0].data = tmp;
    this.chart.update(0);
  }
...
}

Child template:

  <canvas id="canvas" responsive>{{ chart }}</canvas>

How can I solve my problem?

I use Angular 6.

like image 873
Blobonat Avatar asked Jun 21 '18 16:06

Blobonat


People also ask

What causes ExpressionChangedAfterItHasBeenCheckedError?

What is ExpressionChangedAfterItHasBeenCheckedError? The ExpressionChangedAfterItHasBeenCheckedError error is thrown up when the binding expression changes after being checked by Angular during the change detection cycle.

How do I fix ng0100 error?

This often means refactoring to use the correct component lifecycle hook for your use case. If the issue exists within ngAfterViewInit , the recommended solution is to use a constructor or ngOnInit to set initial values, or use ngAfterContentInit for other value bindings.


1 Answers

You can find detailed explanations about that exception in this article. One technique to eliminate the exception is to force change detection with ChangeDetectorRef.detectChanges:

export class ValueChartComponent implements AfterViewInit {

    constructor(private cd: ChangeDetectorRef) { }

    ngAfterViewInit(): void {
        ...
        this.cd.detectChanges();
    }

    ...
}

An alternative technique is to run the handler code asynchronously with setTimeout:

export class ValueChartComponent implements AfterViewInit {

    ngAfterViewInit(): void {
        setTimeout(() => {
            ...
        });
    }

    ...
}
like image 152
ConnorsFan Avatar answered Nov 05 '22 23:11

ConnorsFan