question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`[class]` bindings have different behavior with input/template bindings when ExpressionChangedAfterChecked

See original GitHub issue

🐞 bug report

Affected Package

@angular/core render3 with ivy

@angular/core/src/render3/instructions/styling.ts

Is this a regression?

no

Description

Set an object to the same value(creating another new instance) in the ngAfterViewInit, the [class] binding would report ExpressionChangedAfterChecked error.

it should have the same behavior with the template/input binding, which should not report ExpressionChangedAfterChecked error

related to https://github.com/angular/angular/commit/9d1175e2b2b8bc8b282b15f56daac01e0537a5bf#diff-0c1dbc9c91289ccc01bde8bbb4777691R373-R377

🔬 Minimal Reproduction

ivy can not work in stackblitz now, here is the repo

https://github.com/vthinkxie/ng-class-binding-bug/blob/master/src/app/app.component.ts

import { AfterViewInit, Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    {{ classMap | json }}
    <!-- this won't report error -->
    <app-test [classMap]="classMap"></app-test>
  `,
  host: {
    // this would report error
    '[class]': 'classMap'
  }
})
export class AppComponent implements AfterViewInit {
  classMap = {
    test: true
  };
  ngAfterViewInit(): void {
    this.classMap = {
      test: true
    };
  }
}

🔥 Exception or Error


ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '[object Object]'. Current value: '[object Object]'.

🌍 Your Environment

Angular Version:


@angular-devkit/architect         0.900.0-rc.10
@angular-devkit/build-angular     0.900.0-rc.10
@angular-devkit/build-optimizer   0.900.0-rc.10
@angular-devkit/build-webpack     0.900.0-rc.10
@angular-devkit/core              9.0.0-rc.10
@angular-devkit/schematics        9.0.0-rc.10
@ngtools/webpack                  9.0.0-rc.10
@schematics/angular               9.0.0-rc.10
@schematics/update                0.900.0-rc.10
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2

Anything else relevant?

related to https://github.com/angular/angular/commit/9d1175e2b2b8bc8b282b15f56daac01e0537a5bf#diff-0c1dbc9c91289ccc01bde8bbb4777691R373-R377

cc @kara @AndrewKushnir

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:13 (12 by maintainers)

github_iconTop GitHub Comments

3reactions
pkozlowski-opensourcecommented, Jan 24, 2020

@vthinkxie yeh, as hinted above, I think that the following is going on:

  • currently we don’t have great story for setting “dynamic” class / styles on a host (in a non-destructive way) - things will get better with ivy, but this is not the end of it…
  • our ExpressionChangedAfterItHasBeenCheckedError is not super consistent and sometimes this error is not thrown where (IMO) it should - this is what I’ve meant by “things working by chance”.

Again, thnx for the use-cases, let me dig into it a bit more and comment back on the issue with the findings.

2reactions
vthinkxiecommented, Jan 29, 2020

I got your point Pawel Kozlowski, Thanks for your quick response!

I will discuss this with the rest of the team but don’t hold your breath - I think that the “official” solution will be to use renderer.addClass…

renderer.addClass removeClass setStyle removeStyle works but there are too many boilerplate code when we want to set the class/style dynamicly.

it would be better if renderer could provide equivalent functionality to template className and style binding (like [class] and [style]).

Read more comments on GitHub >

github_iconTop Results From Across the Web

html table - Angular ngFor class binding ... - Stack Overflow
First of all it is this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false' ...
Read more >
Template type checking - Angular
Angular maintains the behavior of the fullTemplateTypeCheck flag, ... Verifies that component/directive bindings are assignable to their @Input() s ...
Read more >
Component - Angular
Maps class properties to host element bindings for properties, attributes, ... NgModule in order for it to be available to another component or...
Read more >
do Bindings in Classes - F# | Microsoft Learn
Learn how to use an F# 'do' binding in a class definition, ... to guarantee that members behave as expected, do bindings are...
Read more >
Structured binding declaration (since C++17)
an expression that does not have the comma operator at the top level (grammatically, an assignment-expression), and has either array or non-union class...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found