Skip to content

Show more details with the ExpressionChangedAfterItHasBeenCheckedError warning #18970

@leocaseiro

Description

@leocaseiro

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

The current warning message ExpressionChangedAfterItHasBeenCheckedError is telling us what are the values before and after the change detection, but there aren't enough information to help to debug.

We are never sure what object or property is referring to. Also, the lines are not always reliable.

In some cases, we use an array of objects and messages like so are provided:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: 
Expression has changed after it was checked. 
Previous value: 'undefined'. Current value: '[object Object],[object Object]'.
    at viewDebugError (errors.ts:30)
    at expressionChangedAfterItHasBeenCheckedError (errors.ts:29)
    at checkBindingNoChanges (util.ts:145)
    at checkNoChangesNodeInline (view.ts:477)
    at checkNoChangesNode (view.ts:568)
    at debugCheckNoChangesNode (services.ts:557)
    at debugCheckDirectivesFn (services.ts:466)
    at Object.View_App_0._co [as updateDirectives] (App.html:7)
    at Object.debugUpdateDirectives [as updateDirectives] (services.ts:443)
    at checkNoChangesView (view.ts:378)

I can see the file name is (App.html:7), so I presume is something in my template, but it's not clear what it is. Also, note that my bug should be on line 2 (<div *ngIf="testObject">), and not on line 7 as mentioned by angular.

Expected behavior

Perhaps, it would be nice adding to the warning message the property/object that has changed its value.

I would expect the warning message being something like so, instead:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: 
Expression has changed after it was checked. 
Previous testObject value: 'undefined'. Current testObject value: '[{a: 1, b: 2}, {a: 3, b: 4}]'.

PS: note the testObject key from my App class, also the values from object as string.

In that case, it would be easier to debug that the object is testObject;

Minimal reproduction of the problem with instructions

This plunker can give an example of the context provided by angular. http://plnkr.co/edit/mX6REf9oidrVeURCvTZG?p=preview

This plunker is a fork from @adrienboulle from #14748 (comment)

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div *ngIf="testObject">
          Object exists
      </div>
      <div class="image-container"
       [ngStyle]="{
         'height': getHeightPx()
       }">
        <img alt="image" style="height: 100%" [src]="getUrl()"/>
        
      </div>
    </div>
  `,
})
export class App implements AfterViewInit {
  img: Image;
  isLoaded: boolean = false;
  testObject: any;

  constructor(private elementRef: ElementRef) {}

  public ngAfterViewInit(): void {
    this.img = this.elementRef.nativeElement.querySelector('img');
    this.isLoaded = true
    
    this.testObject = [{a: 1, b: 2}, {a: 3, b: 4}];
  }

  public getUrl(): string {
    return 'https://angular.io/resources/images/logos/angular2/angular.png';
  }
  
  public getHeightPx(): string {
    if (!this.isLoaded)
      return '0px';

    return '100px';
  }
}

If you comment line 33: // this.testObject = [{a: 1, b: 2}, {a: 3, b: 4}];, you will end up with another bug with the same issue, but now, referring to the getHeightPx() method which was pointed by @adrienboulle on the issue #14748.

App.html:9 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: 
Expression has changed after it was checked. Previous value: '0px'. Current value: '100px'.

In that case, it's much easier to debug. The line 9 is correct.
Also, because of its values ('0px' and '100px'), it is easier to find the property. However, the message error could have the missing getHeightPx() method which would make the debugging easier.

What is the motivation / use case for changing the behavior?

Make it easier to debug this popular error #18129 #17887 #17572 #15464 #14748 and many other issues.

Environment

Angular version: 4.3.6

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions