Data Binding causes ExpressionChangedAfterItHasBeenCheckedError

1k views Asked by At

I'm new to Angular 4. I have a data binding field like below. But somehow, there is an ExpressionChangedAfterItHasBeenCheckedError.

<form>
<div>
  <h2>Hello {{input.value}}</h2>
  <input type="text" [value]="input.value" name="inputTest"/>
  <input type="text" #input [value]="name"/>
</div>
<button type="submit">submit</button>
</form>

Below is a simple constructor:

export class App {
  name:string;
  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }
}

I read a lot of posts about the error, I still don't understand why a simple data binding will cause the error.

I tried below code, but doesn't work.

ngAfterViewInit() {
    console.log("ngAfterViewInit");
    this.cd.detectChanges();
}

Please help!!

Please refer the plunker: https://plnkr.co/edit/16atvKgf2BA6z2OjqT6h?p=preview

1

There are 1 answers

0
Max Koretskyi On BEST ANSWER

As explained in the Everything you need to know about change detection in Angular one of the operations that Angular performs is DOM update. This includes both interpolations and bindings updates. Angular performs these operations for each DOM in the order they are found in the template. These operations are explained in the The mechanics of DOM updates in Angular.

Your template looks like this:

  <h2>Hello {{input.value}}</h2>
  <input type="text" #input [value]="name"/>

So Angular starts updating DOM and first performs update for the h2 element. It evaluates {{input.value}} to an empty string since it hasn't yet updated value binding on the input. So it updates h2 to Hello and remembers the empty string value. Then it proceeds to updating bindings for the input - [value]="name" and sets its value to Angular! v4.3.1. Change detection is finished at this stage.

Then it runs the verification stage as described in the Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error. During verification stage Angular evaluates {{input.value}} and compares it to the previous value. Since input has already been processed the expression evaluates to Angular! v4.3.1 which is different from the empty string that was used for the h2 element during change detection. So you get an error:

Expression has changed after it was checked. Previous value: ''. Current value: 'Angular! v4.3.1'.

It also means that if you change the order of the elements in the template you will see no error. This works OK:

<input type="text" #input [value]="name"/>
<h2>Hello {{input.value}}</h2>