Angular: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked on ng 4

Created on 16 Jun 2017  ·  201Comments  ·  Source: angular/angular

I'm submitting a ...


[ ] Regression (behavior that used to work and stopped working in a new release)
[X ] Bug report #14748 
[ ] 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


After using an observable object in my template using async, I am receiving :
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ''. Current value: 'something'

Expected behavior

Please tell us about your environment


Angular version: 4.2.2

Browser:

  • [X] Chrome (desktop) version Version 58.0.3029.110 (64-bit)

For Tooling issues:

  • Node version: v6.10.3
  • Platform: Mac
core regression bufix

Most helpful comment

I get the same problem after upgrading from 4.1.3 to 4.2.3. Using setTimeout fixes the problem.

from:

PanictUtil.getRequestObservable().subscribe(data => this.requesting = data);

to:

PanictUtil.getRequestObservable().subscribe(data => setTimeout(() => this.requesting = data, 0));

All 201 comments

Had this same issue with using redux. Here is a link to issue I posted on their repository. When on angular 2 there are no errors but on angular 4.2.2 I get expression changed after it was checked errors.
https://github.com/angular-redux/store/issues/428

The problem appears for me on my components when bumping from 4.1.3 to 4.2.x. Reverting to 4.1.3 fixes the problem for me, but that's not something i want to keep forever.

I could reproduce on a minimal project, I'm still trying to figure how to fix this (maybe) regression. But looks like the dirty check has been enforced in dev. mode from 4.2.x. But the changelog is not clear about that. Any tip welcome.

I get the same problem after upgrading from 4.1.3 to 4.2.3. Using setTimeout fixes the problem.

from:

PanictUtil.getRequestObservable().subscribe(data => this.requesting = data);

to:

PanictUtil.getRequestObservable().subscribe(data => setTimeout(() => this.requesting = data, 0));

@jingglang could you please try to reproduce the problem on http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5 with as minimal code as possible?

I'm getting the same issue - upgraded from 2.4 to 4.2, and some of my hide/show logic is now broken. It's accordion-style logic, where visibility depends on comparing the current panel with an observable that holds which panel should be visible (amongst other things). The component uses @select to get the observable, and it's bound with | async in the template - worked like a charm in 2.4, now get the ExpressionChangedAfterItHasBeenCheckedError and the panels don't hide and show on first click, only on second.

I get same issue when updated 4.1.3 to 4.2.2.

But, I found workaround.
Injection of ChangeDetectionRef, and call detectionChanges() function at error point.

constructor(private cdr: ChangeDetectionRef) {
}

onChange(): void {
  this.val += 1; // <- get error after
  this.cdr.detectionChanges();
}

I think this is an issue with the follow change made in 4.2.

https://github.com/angular/angular/pull/16592

to resolve this issue: https://github.com/angular/angular/issues/14321

Do you have any content inside a ng-content tag?

I have the same issue with a form inside a ng-content tag which now errors with the ContentChangedAfter error.

I get same issue when updated 4.1.3 to 4.2.0 or higher

I attach a little project for reproduce the bug

app-error.zip

Following up, I downgraded to 4.1.3 (as advised above) and the error goes away, so whatever the conflict is, it's specific to 4.2. I haven't got time to put together a plunkr this week (or next), but it seems to be related to a single action updating two separate observables on the store, each of which has an impact on the UI. One of the UI updates happens, the other causes the exception.

Hmmm,
Definitely rollback to version 4.1.3 solves the issue and also apply timeout as shown by @jingglang.

hi @tytskyi. I made a plunkr http://plnkr.co/edit/XAxNoV5UcEJOvsAbeLHT for this issue. hope it will help.

the workaround given by @jingglang works (for me) on 4.2.0 or higher
OR also changing the emitting event of the child into its constructor don't raise the error anymore

@umens You update parent component after it was checked therefore you don't keep unidirection data flow

@alexzuza how can I achieve that ? I've always done it this way without the error. Why putting the SetTimout doesn't raise the error anymore. (I updated the plunkr) I doubt it's interfering with the lifecycle or is it ?

hi @umens thank you for your time. The problem is what @alexzuza says: you update parent component field after it was checked. Your code is roughly equivalent to this: http://plnkr.co/edit/ksOdACtXScZKw3VRAYTm?p=preview (notice i removed service, to reduce code).
Why it worked? Probably by accident old version of angular or Rxjs had bug here. Could you please tell which versions was used? Or even put into working plunker?

Why putting the SetTimout doesn't raise the error anymore.

Because you change field asynchronously, which respects one-way data flow.

Lets consider it from the opposite: Why error is raised? First check of Change Detection goes from up to down. It checks app.toolsConfig value bound to template. Then it renders <child-cmp> which synchronously updates app.toolsConfig. Rendering is done. Now it runs second (dev mode only) check of Change Detection to ensure that application state is stable. But app.toolsConfig before rendering child does not equal app.toolsConfig after. All this happens during single "turn", "cycle" of Change Detection.

ok. thank you for the detailed answer. I couldn't find informations about when the child component lifecycle happens.
for the previous "working" version I used:
@angular/* : 4.1.1 (except compiler-cli -> 4.1.0)
rxjs: 5.3.1

@umens here is reproduced error with the old versions you mentioned: http://plnkr.co/edit/kfoKmigXzFXwOGb2wyT1?p=preview. It throws, so probably some 3rd party dependency affected behavior or not complete reproduction instruction?

can't tell.
here is my yarn.lock if you are interested in going further : https://pastebin.com/msARLta1
but i don't know what can be different

I'm seeing similar "ExpressionChanged..." errors after switching from 4.1.2 to 4.2.3.

In my case, I have two components that interact via a service. The service is provided via my main module, and ComponentA is created before ComponentB.

In 4.1.2, the following syntax worked just fine without errors:

ComponentA Template:

<ul *ngIf="myService.showList">
...

ComponentB Class:

ngOnInit() {
  this.myService.showList = false; //starts as true in the service
  ...
}

In 4.2.3, I have to modify ComponentA's template as follows to avoid the "ExpressionChanged..." error:

ComponentA Template:

<ul [hidden]="!myService.showList">
...

I'm still trying to figure out why this has only just become an issue, and why the switch from *ngIf to [hidden] works.

I have the same problem, and it happens mostly when I'm using an async pipe like this:
<div>{{ (obs$ |async).someProperty }}</div>
If I use it like this:

<div *ngIf="obs$ | async as o">
  <div>{{ o.someProperty }}</div>
</div>

Then the error disappear, so I'm not so sure it is only because a lot of people made some mistake that wasn't detected before: I think a bug was introduced in 4.2…

The same problem for me. The issue looks like come from @angular/router

I've also come to the conclusion it's related to the router. Tried to post as much yesterday, but it looks like the post failed. I investigated further and simplified the code to see if I could track down the error. The following code works perfectly when the ultimate source of the action is a click on a panel header, but fails with the ExpressionChanged error when triggered via routing.

<span class="glyphicon pull-right" [ngClass]="{'glyphicon-chevron-up' : (ui$ | async)?.visiblePanels[VisiblePanel.IngredientTypes], 'glyphicon-chevron-down' : !((ui$ | async)?.visiblePanels[VisiblePanel.IngredientTypes])}"></span>

This helped me solving the problem! You have to explicitly trigger the change in the parent.

Like @acidghost, I could solve this problem by running ChangeDetectorRef#detectChanges in AfterViewInit from my parent component.

If you have plunkr repro I'm willing to check on it because we had some similar complains on gitter and it always ended up being an user problem.

Can't be sure if a bug was introduced in 4.2 or if the bug was rather the lack of error on < 4.2 and it got resolved on 4.2.

Error: ExpressionChangedAfterItHasBeenCheckedError
solution:
componentRef.changeDetectorRef.detectChanges();

Below is a piece from my code (dynamically generated components):
componentRef = viewContainerRef.createComponent(componentFactory); //component got created
(componentRef.instance).data = input_data; //manually changing component data over here
componentRef.changeDetectorRef.detectChanges(); // it will result in change detection

For simple components just google how to access "componentRef" and then execute
componentRef.changeDetectorRef.detectChanges();
after setting/changing component data/model.

Solution 2:
I was again getting this error while opening a dialog "this.dialog.open(DialogComponent)".
so putting this open dialog code inside a function and then applying setTimeout() on that function solved the issue.
ex:
openDialog() {
let dialogRef = this.dialog.open(DialogComponent);
}
ngOnInit(): void {
setTimeout(() => this.openDialog(), 0);
}
though it seems like hack.. works!!!

Since 4.2 I have the same problem and no solution or workaround worked for me :( I create a component dynamically with a component factory in a ngAfterViewInit method. This component uses a directive which has an @Input() field. I bind this field to a static string. It seems that the @Input() field of the directive is undefined until the view of the component was build and checked and only then initialized with the static string.

https://plnkr.co/edit/E7wBQXm8CVnYypuUrPZd?p=info

staticComponent.ts

export class StaticComponent implements AfterViewInit {
  @ViewChild('dynamicContent', {read: ViewContainerRef})
  dynamicContent: ViewContainerRef;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  ngAfterViewInit(): void {
    const componentFactory: ComponentFactory<DynamicComponent> = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
    this.dynamicContent.createComponent(componentFactory);
  }
}

test.directive.ts

@Directive({
  selector: '[testDirective]'
})
export class TestDirective {
  @Input()
  testDirective: string;
}

dynamic.component.ts

@Component({
  selector: 'dynamic-component',
  template: `<div [testDirective]="'test'">XXX</div>`
})
export class DynamicComponent {
}

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'test'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?

I am a bit confused reading this thread. Is this a known bug, which will be resolved in an upcoming release? Or, is this expected behavior? If so, what is the solution? Thank you.

No idea if it's related or not, but I hate this message with a passion! this ONLY shows up for me when unit testing with the out of the box 'ng test' command. I suppose I could just be confused about how to successfully mock a simple service. Also surprised no one else has seen this in testing yet, can't find anything test related. I'll be watching this topic and any search for ExpressionChangedAfterItHasBeenCheckedError + unit testing.

I've been trying to put together a plnkr, and finding it very difficult to reproduce the error - however, extensive debugging has, I think, got me a bit closer to seeing what's going wrong (though not to deciding whether it's a bug, or a mistake on my part).

I built a small sample app using cut down versions of the same reducers combined in the same order as in the real app, with the routerReducer last. To my frustration, the error did not occur. So I set breakpoints and watched the flow of actions through the reducers. What I found was the two apps were dispatching actions in reverse order.

My UI reducer manages visibility, and is the source of the state change that's triggering the error. Here is a cut-down version of the reducer, showing the relevant actions:


export const userInterfaceReducer = (state = INITIAL_UI(), action: any) => {
    switch (action.type) {
        case IngredientActions.LIST_INGREDIENTS:
            if (action.hideTypes) {
                return Object.assign(state, { visiblePanel: VisiblePanel.Ingredients });
            }
            return state;
        default:
            return state;
    }
}

When I run this in my small test app, it works - first, the LIST_INGREDIENTS action fires and the new state is returned; then the @angular-redux/router::UPDATE_LOCATION action fires, and the default case is hit, returning the same state.

When I run it in the actual app, the order or actions is reversed. @angular-redux/router::UPDATE_LOCATION action fires first, returning the old state from default. Then LIST_INGREDIENTS fires, returning the new (changed) state - and the error is raised.

I am completely open to the idea that I have done something dumb and this isn't an actual bug - but if so, does anyone else see what I've done?

(As a footnote, I checked the 4.1.3 version ... and it also fires the redux reducers in the 'correct' order - that is, the location change fires after the list ingredients action, which presumably is why it works, but the 4.2 version does not).

Suffering the same annoying bug when one component changes the property of service. Resolved by moving *ngIf to the parent component. So it's definitely a bug

was able to work around this be using ngDoCheck() method and calling the ChangeDetectorRef.detectChanges method.

public ngDoCheck(): void {
    this.cdr.detectChanges();
}

@pappacurds Don't do that. You've caused a infinite Change Detection cycles with that.

might be same error here https://plnkr.co/edit/IeHrTX0qil17JK3P4GBb?p=preview

error: previous undefined after undefiend

after update same error

Same for me

Everything fine in 4.0.0, after upgrading to 4.2.6 I get the same error.

The article Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains in depth why this error occurs and possible fixes

fixes are obvious, but changing the framework in such way that update cause user applications to be rewrite to "support" new minor platform update is wired. JS still maintain old mistakes to hold compatibility...

Same error here

I'm also seeing this issue in ~4.2.4. Downgrading to ~4.1.3 resolved the issue.

Issue is with changing values of ContentChildren, even when using ChangeDetectorRef detectChanges() at the end of AfterViewInit of the parent (where it was making the changes). Oddly this issue only occurs with components and not directives. I converted a directive that I had working in 4.2.4 to be a component with a template of <ng-content></ng-content> and then it began to throw the ExpressionChangedAfterItHasBeenCheckedError error.

I got this while working with material 2 input control. Tried to set the value of it

ngAfterViewInit(): void {
this.numberFormControl.setValue(200);
}

I've put together a simple Plunker showing a case where the ExpressionChangedAfterItHasBeenCheckedError errors only started showing up beginning with Angular 4.2.x.

I've created a simple plunker showing the error when changing a value of a ContentChild even when using ChangeDetectorRef detectChanges() in the parent component's ngAfterViewInit.

Edit: Also created simple plunker based off of my first example but with parent Directive instead of Component and no error.

@saverett I'm seeing a different error message with your plunk

@JSMike I had exactly the same case as in your plunker (worked around it by wrapping code referencing ContentChild in setTimeout, plunker)

@JSMike Thanks for the heads up. Looks like an issue with angular/zone.js#832. I've set the zone.js version to 0.8.12 for now until they fix the latest zone.js. The Plunker should be working again.

@matkokvesic that's not really a solution, that just causes the change to occur outside of the lifecycle hook. The code example provided doesn't cause an error when using Angular v4.1.3

@JSMike I agree, It's a temporary workaround. Using elements referenced by ContentChildren in ngAfterViewInit was working fine prior Angular 4.2.6.

I've fixed it by using changeDetection: ChangeDetectionStrategy.OnPush and this.changeDetector.markForCheck(); in my code

@touqeershafi if you use this.changeDetector.markForCheck(); doesn't it mean you are not using things in right way

This is still happening. This is definitely a bug, not an expected behavior and should be fixed.

@istiti i understand that's not a proper way but at-least you can get rid of this error for temporary, But as far as my project is concern i've already added the TODO with bug url.

This is still happening. This is definitely a bug, not an expected behavior and should be fixed.

I think I have to agree with @rwngallego ... Before the 4.2.x update, I had already written a number of reusable/ng-content stlye components which depend on @ViewChildren, @ContentChildren and create relationships between parent and child through these channels (getting/setting properties and so forth).

I find myself constantly having to inject the ChangeDetectorRef instance into all of these constructors (including child classes which extend this components), and it does not feel like intended or correct behavior.

For the ones using dynamic component like @saverett (using router is using dynamic component) I think it's the problem stated here https://github.com/angular/angular/issues/15634.

For anybody doing changes inside ngAfterViewInit / ngAfterViewChecked I think it's expected.

For the others, (haven't seen any yet here) it's still a mystery to me.

This is happening for me in the following scenario.
Have a parent component which uses a child component. The child component needs data that the parent will supply but this data is coming from a promise result in the parent constructor. So:

parent

constructor {
dataservice.getData().then((result) => {
this.source = result;
});
}

Parent template

<app-child [source]="source"></app-child>

child component

@Input() source:any[];

This code throws this error however adding this to the parent component solved the issue:

constructor(private cdRef: ChangeDetectorRef) {
dataservice.getData().then((result) => {
this.source = result;
 this.cdRef.detectChanges();
});
    }

Now is this a recommended solution or is it a workaround for a bug and what would be the implications of having such change? to me it looks like you are telling Angular to detect changes which I think is something you should avoid so...

@sulhome ... your problem is that the promise in the parent's constructor is changing @Input on the child component ... during CD cycle and its confirmation in dev mode. That is the reason of the error.

The line this.cdRef.detectChanges(); adds the second CD cycle so the confirmation after it is succesful and => no error.

So everything works as expected. It is important to understand how it works to use the right constructs and general logic in your code to avoid these type of problems. You can read about it in the deep explanation here: https://hackernoon.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

@mlc-mlapis so you are saying that I am doing it right by adding this.cdRef.detectChanges(); and that this doesn't have any implications?
I thought by listening to ngOnChanges on the child then I should pick the change in the @Input from parent. is that not the right approach to do it? Please note that I have done that and I was still receiving the error but I thought that's what ngOnChanges is designed for

@sulhome Yes, this.cdRef.detectChanges(); is what helps but it has also the consequence that you have 2 CDs now ... so it depends how and where you are using OnPush strategy on components to eliminate overhead of one more CD cycle.

If it is true that dataservice.getData takes some data using http then probably the easiest solution would be to have an observable in that service and subsribe to it from the child component. So when the data will be emitted on the stream the child can react to it.

@ghetolay for the record, there is some cases when it is a bug, see for example #18129 that I opened.

I have this issue when I get data from child component with @Output.

at parent componet home.ts

drag_second(trigger){ console.log("dragged222222"+trigger); if(trigger){ this.isactive=true; }else{ this.isactive=false; } }
and home.html
<div class="upper" [ngClass]="{'isactive':isactive}">

isactive is changed when dragstart and dragend....

error message is
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.

or is there a any other ways that I can change/add class attribute?

Same issue in 4.2.x and 4.3.0 but not 4.1.x.

Error only occurs on routes that use ng-template.

Solution: Putting all code in ngAfterViewInit into setTimeout solved the problem for me (thanks/credits to @jingglang).

public ngAfterViewInit(): void {
    setTimeout(() => {
        //my code
    });
}

@Wernerson, take a look at JSMike's comment about setTimeout. It's important to note that you are actually just changing the code outside of the lifecycle hook.

My issue was that I used ActivatedRoute's params Observable to modify some state in the ngOnInit(). It seems, that the Router emits the params synchron, so the update happens during CD.
My simple solution for this is currently:

  // !!! see delay(0)
  // results are consumed by async Pipe, where I also had the CD issue (null vs. undefined)
  this.results = this._activatedRoute.params.delay(0)
    .do(params => this.searchParameters = this._createSearchParameters(params))
    .switchMap(p => {
      let key = this.searchParameters.key();
      return this._searchResultCache.results.map(r => r.get(key));
    });

(I know this is not the most beautiful reactive/functional code ever ;) )
So the solution was to delay(0) the parameter emission by one tick.

Hope I can help for others having similar issues.
Also any concerns are welcomed, how my solution is wrong or dangerous.

What's the status of this issue? It's still apparent in Angular 4.2.6.
Is this a problem in production builds? As this error will only happen in debug builds.

I hate all the workarounds with manually running change detection, or even running it in a setTimeout()...

setTimeout() is inefficient, because it causes a new change detection cycle on the whole application, while detectChanges() only checks the current component AFAIK.

My team had a core misunderstanding of what ngOnInit is and isn't. The docs say

ngOnInit(): Initialize the directive/component after Angular first displays the data-bound properties and sets the directive/component's input properties.Called once, after the first ngOnChanges().

We were subscribing to our services (that keep track of application state) from ngOnInit. Our subscriptions are synchronous BehaviorSubjects; they fire at subscription time. So "after Angular first...sets the directive/component's input properties", we were immediately changing the values. Here's a very simple Plunker illustrating that being a problem.

The example in Tour Of Heroes ultimately uses http which is asynchronous, and therefore doesn't cause issues. I think this is the source of our confusion.

What we're doing now is subscribing to our synchronous states from our constructor instead, so that our components' values will be set immediately. Others in this thread have suggested kicking off a second change detection via timeouts, setting values later, or explicitly telling angular to do so. Doing so will keep the error from appearing, but imho it's probably unnecessary.

The article that @maximusk shared is a must read: Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error.

If nothing else, this thread should result in an in-depth warning of all this in the official angular docs.

The article that @maximusk shared is a must read: Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error.

Thank you

@adamdport

Does this work in the case of using @ViewChildren @ContentChildren to modify child properties from the parent, since the children are not available until the ngAfterViewInit() lifecycle has been executed?

Please keep in mind that a part of this issue is a confirmed bug and not a user fault:
https://github.com/angular/angular/issues/15634

The problem @saverett addressed is correct, using *ngIf was causing the error.

*watching...

This can happen if you pass objects to a Angular Material dialog and then in the dialog use them directly rather than doing this.myDataInput = Object.assign({}, dialogDataInput). I.e. this.myDataInput = dialogDataInput; and then doing something like this.myDataInput.isDefault = !this.myDataInput.isDefault;. Like explained above, the child component (dialog) is changing values that are exposed in the parent component's view.

replace attribute with [attribute]

Does anyone know for sure if this is an intended error or a bug?
Isn't it correct to load data in ngOnInit? Because if I move the code to the constructor (loading through an Observable) the error isn't thrown...

@Wernerson . Do you have *ngIf in your html? beware that things are going to be rendered after ngOnInit has finished, solong, everything inside *ngIf won't work and might lead to this error.

It has to be reworked. With "ngIf" and custom controls you get this error message. A timeout is certainly not a solution.

@j-nord if you'd read the comments, you'd know that timeout isn't required.

@j-nord / @dgroh I've experienced the same. I've been using an ng-hint which uses an ngIf directive and I cannot get rid of this error. Did you manage to implement a workaround?

@Wernerson yes, a part of this issue is an intended error or a bug: https://github.com/angular/angular/issues/15634

@mawo87 it worked for me with hidden as it does not remove the element from the DOM. For our requirement this was ok and was also a clean solution.

@mawo87
First you have to find the variable which is meant by the error message. @Angular Team: It would be nice to have the name of the variable in the error message. This is not easy to find by larger masks and Webpack. If you found the command where it happens, the command in the follow line will help:

this.cdr.detectionChanges();

See the example from vermilion928 from 19.Jun.

Thanks @dgroh and @j-nord.
@j-nord I was also looking at the detectionChanges method, but I might not use this approach as in the following article it was advised against it:
https://hackernoon.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

In my case, I'm using a PageTitle service and subscribing to it in the parent component, and then as child components are loaded into view, they set the PageTitle in the service and the parent gets the value and displays it via the subscribe. This worked without any errors in 4.1.x, but throws the ExpressionChangedAfterItHasBeenCheckedError error in 4.2x and later.

Everything still works as expected, and the errors don't display in deployed/production builds (due to the lack of a second change detection cycle), but in development there's an awful lot of red in my console.

I'm still extremely unclear as to what the appropriate (even short term) fix is. My parent component subscriptions are in the constructor, and the child component updates via the service are in ngOnInit.

I've read the 'everything you need to know about...' post, which was informative, but doesn't lead me to believe I'm doing anything incorrectly, and does't provide a working solution to the problem.

@alignsoft if you would set the pagetitle in the child components in the ngOnInit, then I believe the error is valid... See the article that was linked before.

@alignsoft I agree, there has been a lot of discussion around this error, but without real clear instruction on whether its valid or not... is this more of a "warning" to the dev about standards and data binding/manipulation?

In my specific case, I'm dealing with parent/child components using @ViewChild and @ContentChild, having to call detectChanges() over and over to stop the error from showing in the console...

@rolandoldengarm I've tried subscribing in the parent constructor and setting the values in AfterViewInit in the child components and still get the error. Is that the correct way to handle this based on the flow and change detection cycle, and the error is potentially a bug?

Please, it would be great to have some kind of official answer here ...

Looking at this again. Looks like my example from https://github.com/angular/angular/issues/17572#issuecomment-315096085
should have been using AfterContentInit instead of AfterViewInit when trying to manipulate ContentChildren as part of the component lifecycle.

Here's the updated plnkr with AfterContentInit and no more error: http://plnkr.co/edit/rkjTmqclHmqmpuwlD0Y9?p=preview

@JSMike I changed AfterViewInit to AfterContentInit, still the same error. Even if I update my data inside OnInit the error occurs. As far as I know this is according to the Angular lifecycle correct (right?) to initialize data during OnInit. Together with the fact that this error didn't occur in past versions I assume this is a bug. However I would like to have some kind of statement from the development team if that is so..? :D

@Wernerson you shouldn't be updating data inside ngOnInit unless the data is available at that lifecycle hook. You should move your logic to be in ngAfterContentInit if it has to do with content children.

@JSMike Didn't help, the error still occures. I just subscribe to a state change in the application after I received the data requested (asynchronously) in ngAfterContentInit.

@Wernerson do you have a plnkr example?

Basic sample with StackBlitz
A child component emitting an event and parent component updating local variable.
Get error in js console :
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'hello world'.

Found out, thengAfterContentInit only works if the children are static, it still fails when creating children using *ngFor http://plnkr.co/edit/rkjTmqclHmqmpuwlD0Y9?p=preview

@soldiertt you just need detectChanges() https://stackblitz.com/edit/angular-qfu74y

@JSMike if i do this, ngAfterViewInit of child component is not triggered : https://stackblitz.com/edit/angular-bdwmgf

@soldiertt that seems odd, but looks like a separate issue that should be reported.

@JSMike My setup is fairly complex with services, third party libraries, confidential information, etc. etc. Unfortunately I couldn't reproduce the bug in a plunker :/

Injection of ChangeDetectorRef worked for me!

I have this issue in a carousel, because I need to set some property on the carousel item component, property which is only known after computed in the parent carousel component. And all the items are coming through ng-content, so I can only work with the items in the ngAfterContentInit of the parent carousel component. Something like:
carousel:

@ContentChildren(ItemComponent) carouselItems;

ngAfterContentInit() {
  // ... some computations
  this.carouselItems.forEach((item: ItemComponent, currentIndex) => {
    item.setPropertyX(someComputedValue);
    // OR:
    item.x = someComputedValue; // of course, this would work as well
  });
}

item:

setPropertyX(value) {
  this.x = value;
}

Besides the setTimeout() hack, would the only other solution be to use a service and a subject to have the items communicate with the parent carousel? I mean that would be ridiculous... That would mean that, if I have 100 items in a carousel, then I would have 100 subscriptions. And that doubles if I have 2 carousels. Surely that can't be the recommended way?! Right?

More often than not, we would need to set some properties on our components, properties that can't be known before AfterContentInit... And in many cases (when we're not talking about 1 or 2 components like that, but rather 50 or 100 like in a carousel) having tenths or hundreds of subscription would be ridiculous.

Is there some really cool part of Angular that can help me here, that I haven't yet discovered?

P.S. I've also tried to inject ChangeDetectorRef and use detach() on both carousel component and item component. I would have expected this to fix the error since, well... I'm basically saying "_screw change detection, I don't actually need it at all. Please, pretty please: don't detect ANY changes_"... but the error is still thrown! So, what's the point of the detach() method, if it doesn't do what it says?

constructor(private cdr: ChangeDetectorRef) {
  this.cdr.detach();
}

setTimeout() isn't necessary a hack it may be the very valid way of doing things like for example when you react to view to update it e.g: changing template's bindings during ngAfterViewInit.

The problem is when you use it as magic without really knowing why. But there are totally valid scenario where using setTimeout() is the proper way.

@ghetolay Is it not hacky to break out of the lifecycle of the component(s) the change detection system is evaulating? I've been going the ChangeDetectorRef.detectChanges() route, but that even feels like a hack to me... if either of these solutions are "acceptable" I suppose we'll have to live with it, but it really breaks any use of ViewChild(ren) or ContentChild(ren) modification

@fugwenna

Is it not hacky to break out of the lifecycle of the component(s) the change detection system is evaulating?

I don't understand that question. break out of the lifecycle ?

Angular will run a round of CD each time an async events occurs (dom event, xhr, setTimeout etc..), during that CD it will update the view. ngAfterViewInit hook is run after that so there is no more CD planned to run and it wont be triggered again until another async event occurs. Using setTimeout() is the simplest way to trigger it again. You could certainly do it yourself but I think the benefits are negligible.

@ghetolay I am referencing the comment from @JSMike and some other threads I've read:

@matkokvesic that's not really a solution, that just causes the change to occur outside of the lifecycle hook. The code example provided doesn't cause an error when using Angular v4.1.3

So I think using a setTimeout() will cause the lifecycle hook to be "skipped" or not evaluated as it normally would be?

@ghetolay @fugwenna what about the detach() method of the ChangeDetectorRef? Any thoughts? Shouldn't that disable change detection completely, thus also eliminating the error? I don't understand why it doesn't work? Or is the error thrown "independent" of that? Meaning that Angular doesn't really care about the fact that we've disabled change detection, it only cares that we've changed a property after it has been set?
If people still argue about the "ExpressionChangedAfterItHasBeenChecked" being a bug or not, maybe this one definitely is a bug... In my opinion, Angular should no longer care about us changing properties after they've been set, if we've completely disabled change detection. Especially the way I did it, for the parent component and all other child components, on an entire tree basically.

I'm a bit lost here, one of the problem I have is that I'm not sure how i would even do some very common things without triggering the exception in dev mode.

For instance I've written a control value accessor component which encapsulates a datepicker. I feed this component with an empty model that is passed to the datepicker internally which initialize it and send it back through the registered function. Of course the children modifies the model during its init, but that's what I want ! I want to get back an initialized model but not do the initialization in the parent because it is the datepicker who undertand how to do that.

The issue is how would I do that now ? Call setTimeout and trigger change detection again ? Use ChangeDetectorRef ? I don't like it because it really make the code hard to read. Initialize thing in a separated service ? But that service is only serving a very technical purpose without any business value and I'm not even sure this will solve the issue.

@fugwenna My main concern was that it worked in 4.1.3 and is now broken. I haven't seen anyone on the angular team chime in yet on if we should be using setTimeout in our init functions and letting zones take over, but it feels like an anti-pattern compared to how it worked previously.

@kavi87 So this stackoverflow question actually gave me the elegant solution I needed. Which was to make the event emitter in my child component async:
new EventEmitter(true)

For an issue labeled as a regression with 109 comments this issue is disappointingly quiet with any official word.

While everyone here is doing a good job with the self-help techniques, I'd love to know if this is actually a bug, or just some new behaviour implemented in 4.2.x onwards? If so it should have been listed as a breaking change (and thus not a minor release?)

@MrCroft
I'm not sure disabling change detection entirely to silence an exception is a good path to go down, although in theory, I see how it should/could make sense.

I agree with @JSMike and @rosslavery in regards to very little response or explanation as to why this error message came about post 4.2x without any documenation of breaking changes... however another puzzling piece of this is how it is apparently only thrown in development mode, which almost feels like more of a warning of interrupting change detection (?)

Im my AppComponent I have an div.
The only purpose for that div is to show a busy overlay.
The busy state is triggered inside an http service class:

app.component.html

<!-- Busy Overlay -->
<div *ngIf="busy$ | async"
     class="overlay">
    <i class="loading">
        <i><sk-wave></sk-wave></i>
    </i>
</div>

app.component.ts:

  get busy$(): Observable<boolean> {
    return this.catolService.busy$;
  }

After upgrading to 4.3.4 I always get an ExpressionChangedAfterItHasBeenCheckedError when the service triggers the busy state.

Is there a fix for this simple asynchronous scenario?

@mukunku Thanks, I will try that.

@mlc-mlapis I slightly changed your plunker my code is exactly https://plnkr.co/edit/uUT7tiM5BKPIy2upJPhb?p=preview

but the plunker doesn't show the issue. I'll try to upgrade to latest 4.x to see if it's been fixed.

Thanks

Hi all - apologies on the delay here.

So - this behavior is actually working as intended, which I realize might be unexpected for some folks, so let me try to explain the mechanics.

@saveretts' plunker is a good repro of this to walk through (thanks!) - https://plnkr.co/edit/fr7rTNTCgEhHcbKnxAWN?p=preview

The tldr is that Angular has always worked this way - change detection is running, top to bottom (or parent -> child), in a single pass. So, if we have:


@Component({ 
  selector: 'app-root',
  template: `
    <!-- initially falsey -->
    <div *ngIf="sharedService.someValue">NgIf Block</div>
    <child-comp></child-comp>
  `
})
class AppRoot {
  constructor(public sharedService:SharedService){}
}
@Component({ 
  selector: 'child-component',
  template: `child comp`
})
class ChildComponent {
  constructor(public sharedService:SharedService){}
  ngOnInit(){
    this.sharedService.someValue = true;
  }
}

Change Detection will run for the app-root first, check all of its bindings, and then change detect the child component - again, because we do this in a single pass (rather than AngularJS-style keep checking until stable), the parent binding (the *ngIf, in this case) isn't re-checked - so now your application is in an inconsistent state (!)

In development mode, we actually run that change detection twice - the 2nd time it runs verifies that bindings have not changed (which would indicate inconsistent state), and throws the error if such an issue is found. You can verify this behavior by calling enableProdMode() in the repro: https://plnkr.co/edit/GGEzdxK1eHzHyGiAdp56?p=preview. Note that the error is not thrown (because we're not running CD x2), but the application ends up in an inconsistent state (the child is shown, but not the *ngIf), which is a Bad Thing.

The reason this surfaced recently is that previously, the router ran a number of additional change detection checks when inserting components - this was inefficient and caused issues with animations and routing, especially when router-outlets are nested in ngIfs and such things. That behavior was fixed, which caused already-incorrect code as above to now *correctly throw an error that the developer is violating one way data-flow.

I would argue that typically, code that violates this one-way flow (as the repro above does) is incorrect. However - there are cases where you might want this behavior (in fact, we have a similar setup in the Angular forms library). What this means is you need to explicitly trigger another change detection run (which would go back to the root component and check top-down). Calling setTimeout achieves this, though typically it's better to use a Promise to trigger this - see https://plnkr.co/edit/IoKMxEOlY9lY9LcWwFKv?p=preview

Hope that helps!

@robwormald This same error was occurring with other scenarios as well. I'm not sure if this addresses the issue with ContentChildren. Why can a Directive can change the values of children during AfterContentInit without error but doing the same in a Component throws errors?

Also, is it expected that if a cdr.detectChanges() is called during one init process that the other init functions end up not getting called? This is something discovered in this thread that I created a separate issue for.

@robwormald

I believe @JSMike is correct in the assessment that this error is still thrown during scenarios where the one-way flow is coming from a Parent->Child using ContentChild(ren) and ViewChild(ren).

Is it acceptable to consider what I've said before, that is this error more of a "warning" which states that the developer is going against the one-way flow "best practice" but not causing any application breaking errors, since change detection only runs once during production mode (real world)?

@fugwenna No, this is really an error, as it otherwise leaves the view in an inconsistent state. The sample Rob is running through is telling it all.

Also, there is this quote from the docs

Angular's unidirectional data flow rule forbids updates to the view after it has been composed. Both of these hooks fire after the component's view has been composed.

If you really need to change anything there, use one of the async methods to do so. setTimeout might be suited here, but be aware that that comes with an (at the time of this writing) 4ms delay of its own. Another way is Promise.resolve().then(() => Assignment = here)

Even better is taking a step back, and see why you need to make a change this late in the process and see if there is a cleaner way to solve the issue. If I find myself doing this, I treat it as a code smell.

Thank you for the detailed explanation @robwormald. I'm still confused why a child -> parent data flow still seems to work when using a [hidden] binding rather than *ngIf (see https://plnkr.co/edit/L4QWK5pTgF1qZatFAN4u?p=preview). Any ideas why this still works without giving an ExpressionChangedAfterItHasBeenCheckedError?

Angular uses checkAndUpdateView function to perform change detection.

Short representation of this function could look like:

function checkAndUpdateView(view) {
    // update bound properties and run ngOnChanges/ngOnInit/ngDoCheck for child directives
    updateDirectives
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
    // update DOM for the current view
    updateRenderer
    // perform checkAndUpdate for all child components
    execComponentViewsAction(view, ViewAction.CheckAndUpdate);
}

It is executed recursively thanks to execEmbeddedViewsAction and execComponentViewsAction methods. And also key point here is angular checks embedded views after directives have been checked and before updating DOM.

To simplify @saverett example i will use the following template

<div *ngIf="!sharedService.displayList">Some text</div>
<router-outlet></router-outlet>

https://plnkr.co/edit/OdkzHjEXbEd3efYAisFM?p=preview

We have already known that *ngIf is just desugar. So

<ng-template [ngIf]="sharedService.displayList">
  <div>Some text</div>
</ng-template>
<router-outlet></router-outlet>

We can imagine the following structure:

  my-app
     |
   NgIf directive
       NgIf EmbeddedView
   RouterOutlet directive

What does RouterOutlet directive do?

It injects routed component into ViewContainerRef

activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
    ...
    this.activated = this.location.createComponent(factory, this.location.length, injector);

It means that router-outlet creates EmbeddedView so after RouterOutlet directive initializes we have two embedded view in our AppComponent view.

  my-app
     |
   NgIf directive ([ngIf]="sharedService.displayList")
       NgIf EmbeddedView
   RouterOutlet directive 
      BComponent EmbeddedView

Let's illustrate it in the picture

haschanged

Now let's come back to our main function

function checkAndUpdateView(view) {
    // update bound properties and run ngOnChanges/ngOnInit/ngDoCheck for child directives
    updateDirectives
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
    ...
    // update DOM for the current view
    updateRenderer
    ...
}

Angular will perform check in the following order:

NgIf directive ([ngIf]="sharedService.displayList") updateDirectives(1)
      NgIf EmbeddedView   execEmbeddedViewsAction(2)
RouterOutlet directive 
      BComponent EmbeddedView  execEmbeddedViewsAction(3)

Our NgIf directive will be checked first (here sharedService.displayList=false is remembered) and then NgOnInit method inside BComponent will be called (where we're changing sharedService.displayList to true) And when angular performs checkNoChanges it will raise the error Expression has changed after it was checked

Then let's replace *ngIf with [hidden]. Now we will have only one embedded view inserted by RouterOutlet and our [hidden]="sharedService.displayList" will be checked within updateRenderer

  my-app
     |
   div{Some Text} just a node
   RouterOutlet directive 
      BComponent EmbeddedView

Angular will perform check like this:

function checkAndUpdateView(view) {
    // check all embedded views that belong current view
    execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);   BComponent.ngOnInit (1)
    ...
    // update DOM for the current view
    updateRenderer   update hidden binding (2)
    ...
}

This way dom property binding won't cause the error because we have updated after calling ngOnInit value.

That's the main difference between structural directive *ngIf and dom property binding [hidden]

Thank you for the detailed overview @alexzuza! It was very helpful!

setTimeout() actually worked for me :) Thanks @jingglang :)
.subscribe(data => setTimeout(() => this.requesting = data, 0))

@robwormald is correct here. I had the same issue and it was more difficult to detect because I was using NGRX and observables. The issue I had was that there were component containers at different levels in the route hierarchy that were subscribing to the store state. As soon as I moved my container components to the same level in my feature module, the issue went away. I know this is sort of a convoluted answer but if you happen to be using NGRX container/component pattern hopefully this points your investigation in the right direction

With setTimeOut it works, thanks @jingglang
ngAfterViewInit(){
this.innerHeight = (window.innerHeight);
setTimeout(() => this.printPosition(), 0);
}

@alexzuza , this not happening just for ngIf, this happening (at least for me) also with [ngClass]

@Ninja-Coding-Git I just described specific case. I know that it can happen with any code.

For me, calling ChangeDetectorRef after changing the element solved the problem:

import { Component, ChangeDetectorRef } from '@angular/core'

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App {
  message: string = 'loading :(';

  constructor(private _cdr: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.message = 'all done loading :)'
    this._cdr.detectChanges();
  }

}

Solution found here

hello @thetylerb! could you elaborate more on this. We're using ngrx and i just dont know how to compensate for this. I think using promises on top of observables is pretty awkward.

@piq9117 you can also take a look at this comment https://github.com/angular/angular/issues/18129#issuecomment-326801192 I made on the interaction between change detection and ngrx, it can be helpful I suppose

@victornoel thanks! That pretty much describes our situation. We got nested immutable data structures(immutablejs), and we're using async pipes everywhere. My initial thoughts were, the store would change the component tree when the store has been hydrated, and the component tree would just compensate for this change and do another changeDetection 😓

We got nested immutable data structures(immutablejs), and we're using async pipes everywhere. My initial thoughts were, the store would change the component tree when the store has been hydrated, and the component tree would just compensate for this change and do another changeDetection.

In my project we have some kind of normalized datastructure (instead of nested data structures), so it mitigates a bit this kind of problems, until it does not! :O

You only hope is either:

  • changing you store datastructures so that changes to one part does no trigger updates to other parts
  • being careful not to trigger events from childs of components that listen to the store via async pipe
  • triggering manually change detection when you trigger the aforementioned events
  • trigger those event at another time or in a setTimeout

I am using ngrx and got situation like this:

In app.component.html:
<div *ngIf='(appState | async).show'>test</div>
And in app.component.ts
this.appState= this.store.select("app");

Of course in this situation i get the error, but when I add boolean flag in component like this:
app.component.html -> <div *ngIf='show'>test</div>
app.component.ts ->
this.appState.subscribe((state: AppState) => { this.show= state.show; })

The error is gone, of course it is understandable for me why, but I want to know your opinions, is it a good solution? What are pros and cons??

Not using ngrx but am having the issue with a simple check with querySelectorAll let chips = [].map.call(document.querySelectorAll('li.chip'), this.chipVisible);

@bogdancar's solution with ChangeDetectorRef.detectChanges() suppresses the error but it would be nice to not have to import ChangeDetectorRef by fixing whatever is causing the error in the first place.

I got the same issue when I using rxjs in angular 4.4.4. I just subscribe a observable object provided by DI service. My work around below:

this.eventBroadcastService.getCustomEvent({type: 'loginOpen'}).subscribe(e => { setTimeout(() => { this.isBlur = true; }, 0); });

I use a setTimeout to work around. Now it works, but it's tricky. I feel no good.

ngOnChanges(changes: SimpleChanges | any) does the trick

The issue was fixed simply after moving the dynamic changing parameters logic inside the ngDoCheck() method.
ngDoCheck(): void { this.checkValid = this.sourceArr.includes((this.chanedVal).toUpperCase()); }

@asrinivas61 I think this is a really bad idea. ngDoCheck is getting called a lot by Angular and if your sourceArr has a lot of data it might hurt your perfs.

See https://angular.io/guide/lifecycle-hooks#other-angular-lifecycle-hooks

I would rather recommend for now using ngAfterViewInit with setTimeout:

setTimeout(_ => /* your code here */, 1000);

example:

  public ngAfterViewInit(): void {
    // We use setTimeout to avoid the `ExpressionChangedAfterItHasBeenCheckedError`
    // See: https://github.com/angular/angular/issues/6005
    setTimeout(_ => this.isLoadingInProgress = false, 1000);
  }

@dgroh you don't need to add an actual timeout, you just want js to execute your code in a next async task which means another change detection run.

@victornoel I barelly believe this would work with observables unless you explicit call detectChanges of ChangeDetectorRef. I wish all this was not needed.

@dgroh you must have misunderstood me, I was just advocating for writing:

public ngAfterViewInit(): void {
    // We use setTimeout to avoid the `ExpressionChangedAfterItHasBeenCheckedError`
    // See: https://github.com/angular/angular/issues/6005
    setTimeout(_ => this.isLoadingInProgress = false);
  }

Is it not possible to add a step after ngAfterViewInit like a setTimeout? (for example : ngAfterViewLoad)

@aks4it, this does seem to work, but I'd love more details on how it does? Is the dynamic component generation code synchronous?

Official plunker demo from angular docs has same error. Could you fix it there? :) Thanks

@luckylooke

  ngAfterViewInit() {
    //this.loadComponent();
    this.getAds();
  }

this works?

i don't understand your requirement but you really want interval of 3seconds ? if yes this works, and even if you want directly call loadComponent I succeeed with:

ngAfterViewInit() {
    setTimeout(()=>{this.loadComponent()},0)
  }

@istiti I was able to fix it by ChangeDetectorRef workaround, putting detectChanges() after ...data = data

But since it is plunker from official docs, I was curious about official solution of the problem. Not timeout or ChangeDetectorRef.

Sorry I was too brief in first post.. I wanted to point out the severity of the problem, as even the angular docs have the same in code.

Just FYI, I'm not sure what's really causing here, But errors are gone when i enabled prod mode in main.ts
`enableProdMode()

// if (environment.production) {

// enableProdMode();

// }`

"@angular/core": "^4.2.4"
"typescript": "~2.3.3"

@bakthaa ... it is supposed behavior because the control check (whether components @Inputs() values are the same) which is called after each CD cycle is invoked only in development mode and not in production mode of Angular app. So the problem is hidden in production mode but it is still there ... and probably can be a source of different unwanted or mislead side effects in production mode.

I'm using Angular 5, I was able to fix this problem by Injecting the ChangeDetectorRef in component and forcing it to detect changes.

    constructor(private changeDetector: ChangeDetectorRef) {}

    ngAfterViewChecked(){
      this.changeDetector.detectChanges();
    }

@Sabri-Bouchlema ... yes, it is one way ... but still you should re-think once more ... why a component @Inputs are changed during one CD cycle ... and decide if the logic is correct ... and it is true that from 95% of cases the code is possible to change to avoid the problem without calling additional detectChanges().

Using angular 5.1.2. I am getting this error when opening a material dialog in ngAfterViewChecked. As @aks4it reported, I had to wrap the code into a setTimeout to make it work.

I'm facing the same issue with version 4.01
ng-version="4.0.1

Same here with angular 4.4.6

Fix using the this.changeDetector.detectChanges();

I have writen this plunker using template variables and I don´t understand why I have ExpressionChangedAfterItHasBeenCheckedError . If i change order in my components, error disappers:

https://plnkr.co/edit/Mc0UkTR2loI7wgmLAWtX

I have tried changeDetector.detectChanges but not works

@AlexCenteno ... because the evaluation logic is from top to bottom ... and value property of comp1 is set @Input() public value:String=null; first and then re-set using the reference of comp2.value ... <div comp1 [value]="comp2.value"></div> which is set meantime to Hello via its own @Input() ... all withing one CD cycle ... so the repeated checking if inputs on child components are the same as on the beginning of CD cycle in dev mode detects the change in value property on comp1.

hi @mlc-mlapis thank you for your time. So there's no way to avoid the error? I guess it's something I should not worry about once I call enableProdMode?

@AlexCenteno ... yes, in prod mode the checking after CD cycle is not invoked ... but it doesn't mean that you should be satisfied with that. You should apply a different logic of passing the value cross child components. There is also a problem that <div> doesn't have a property value. Why do you use attribute component at all? Why not just:

<comp1 [value]="comp2.value"></comp1>
<comp2 #comp2 value="Hello"></comp2>

because then using @Output() on <comp2> would be fine and it would allow you to update [value] on comp1 without any error.

Using [email protected] with angular@5 standart store.select throw warning ExpressionChangedAfterItHasBeenCheckedError in dev mode and incorrectly work at prod mode. Dispatching and selecting are at different levels/containers.

@Component({
  ...
  template `
  ...
      <div [ngClass]="{
        'home__sidenav': true,
        'home__sidenav--active': (isActiveSidenavMenu$ | async)
      }">
  ...
  `
})
export class HomeContainer {
  isActiveSidenavMenu$ = this.store.select(fromHome.isActiveSidenavMenu);
  ...
}

This approach remove the warning message, but it's seems to be more complicated:

@Component({
  ...
  template `
  ...
      <div [ngClass]="{
        'home__sidenav': true,
        'home__sidenav--active': isActiveSidenavMenu
      }">
  ...
  `
})
export class HomeContainer {
  isActiveSidenavMenu$ = this.store.select(fromHome.isActiveSidenavMenu);
  isActiveSidenavMenu;

  ngOnInit() {
    this.isActiveSidenavMenu$.subscribe(res => {
      this.isActiveSidenavMenu = res;
      this.cd.detectChanges();
    });
  }
}

Is there any idea how to solve this problem more correctly?

@rimlin have you tried just directly subscribing to the store?

ngOnInit() {
  this.store.select(fromHome.isActiveSidenavMenu)
    .subsbrice(res => {
      this.isActiveSidenavMenu = res;
    });
}

i think i had a similar problem. and by avoiding async in the template solved the problem.

@piq9117 thanks for advice, tried your solution, it seems are more clear with less code, but here also need to call this.cd.detectChanges();, otherwise view will not updated.

ngOnInit() {
    this.store.select(fromHome.isActiveSidenavMenu).subscribe(res => {
      this.isActiveSidenavMenu = res;
      this.cd.detectChanges();
    });
}

I'm using Angular 5.2, i did something like that. Works for me

constructor(private changeDetector: ChangeDetectorRef) {}

ngAfterViewInit(){
  this.changeDetector.detectChanges();
}

Using Angular 5.2, fixed using detectChanges()

Yes, we fixed this using the detectChanges() route as well (Angular 5.1). I am with many others here though that thinks this is still just a workaround and shouldn't be treated as the answer in the long run. There should be another lifecycle hook to be able to use.

Triggering an entirely new change detection cycle to allow changes like this just seems sub-optimal.

This seems to keep going on and on even though all of the answers and advice has already been posted above.

  1. The right way to fix this is to re-architect/restructure your components and data handling to work with a single change detection pass from the top down. This means that no child component may change a value that is used in the template of a parent component. Re-evaluate what you have built and verify that the data flows only in one direction, down the component tree. This may be as simple as moving your code out of ngAfterViewInit and into ngOnInit in some cases.
  2. this.changeDetectorRef.detectChanges(); is the official and recognized way for handling this in the less than 5% of cases where the first step is problematic.

Other notes:

  1. Be very careful when doing anything in ngAfterViewInit as changing values that are used in the DOM can cause this error.
  2. Be very careful when using any of the Check or Checked lifecycle hooks as they may be called on every change detection cycle.
  3. setTimeout can work around this, but the two solutions above are preferred.
  4. Ignoring this error in dev mode and being happy that production mode "fixes" the error is not valid as explained above. These checks are not made in prod mode, but your prod mode code is still leaving changes undetected and causing the view and data to be out of sync. This can be harmless in some cases, but can lead to data/view corruption and worse problems if ignored.
  5. One way data flow hasn't really changed a lot in Angular, so posting that you hit this in version X of Angular isn't too helpful.
  6. Adding more lifecycle hooks or states is not a solution to this. Developers would just add code that violates one way data flow into those hooks and trigger this same error.

Finally, just remember that this error is not indicating a problem with Angular. This error is here to let you know that you have done something wrong in your code and that you are violating the one way data flow system that makes Angular fast and efficient.

The posts above and many blog posts go more deeply into this and are worth reading as you should understand this one way data flow model and how to build components and pass data within it.

@Splaktar Would it be better to lock this issue (and delete me) to make the above comment outstanding? The thread already gets too long and most of them were just repeating. 😃

@Splaktar You make this point "This means that no child component may change a value that is used in the template of a parent component".

Suppose you have a container component that includes navigation, page titles etc., and it loads a collection of sub-components, each which may load their own sub-components. The components loaded into the container will change based on data, and the sub-components they load will change based on data. Each of these sub-components needs to be able to communicate back to the parent container information about what they are so that the parent container can display the appropriate top level Nav to the user perhaps (breadcrumb trail perhaps, or something similar), as well as information that can be used in titles to identify at the container level what's loaded into view.

In this, which is an extremely common architecture in my experience, I would make use of a common state service which the sub-components would register themselves with, and the parent component subscribes to so that the children can educate the parent, and the parent can display the appropriate information.

This isn't following a bottom up approach, as the parent would get all the relevant data from the service, and push any information required by the child components down via one-way communication.

This seems to run counter to what you're suggesting above, and for me is the source of the problem. When the child component registers with the service, the parent component throws the error.

Is this incorrect?

And never forget, that there is an approved bug:
https://github.com/angular/angular/issues/15634

@alignsoft ... do you have a simple reproduction of your case and the problem as a Stackblitz? Because it looks that something else should affect the case than just the logic you described.

@trotyl the solutions from @Splaktar are not related to my simple problem here https://github.com/angular/angular/issues/17572#issuecomment-311589290 or?

@Martin-Wegner ... in your case it is enough to change ngAfterViewInit to ngOnInit hook.

@alignsoft, as @mlc-mlapis said a Stackblitz example would be very helpful in demonstrating the proper architecture for this case. This is very much possible using the right set of services, observables, lifecycle hooks, etc. This specific case would also be a good topic for StackOverflow.

@Splaktar Once I get my current deadline off my desk I'll mockup a project that demonstrates a simple case.

@mlc-mlapis wow thanks, it works :)

@alignsoft, today I was creating an app that behaves exactly like you've described. @mlc-mlapis, you can find the stripped down example on stackblitz. If you click on "CMS System" on the left nav, the ExpressionChangedAfterItHasBeenCheckedError exception will be thrown.

In the example, the admin.component acts as a parent component in charge of 3 things:

  • displaying a left nav
  • a top ticker that sub components can use to display their own ticker message
  • a main content section that displays sub component specific data through <router-outlet></router-outlet>.

Parent Component

<div class="ticker-container" *ngIf="tickedMessage !== ''">
  <h1>{{tickedMessage}}</h1>
  <button type="button" (click)="tickedMessage = ''">
    close
  </button>
</div>

<div class="side-nav">
  <h2>side nav</h2>
  <ul>
    <li><a routerLink="/">dashboard</a></li>
    <li><a routerLink="/apps/thirdpartycms">CMS System</a></li>
  </ul>
</div>
<div class="main-content-container">
  <router-outlet></router-outlet>
</div>
export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      On the side nav if you click on CMS System, this piece of code throws the exception: 
      "ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed 
       after it was checked. Previous value: 'false'. Current value: 'true'.""
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe((tickedMessage: string) => {
      this.tickedMessage = tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

In researching how to communicate data back up to the parent component when using <router-outlet></router-outlet>, I read that if I use @Output to send data back to the parent component, the router-outlet directive will end up handling the event. Since it’s a custom event, the router-outlet directive will not know how to handle it. So I skipped this method. Once I read about shared services at angular.io I wrote my own:

Shared Service

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class AdminService {

  private _tickedMessageAnnounced = new Subject<string>();

  tickedMessageAnnounced$ = this._tickedMessageAnnounced.asObservable();

  announceTickedMessage(tickedMessage: string) {
    this._tickedMessageAnnounced.next(tickedMessage);
  }
}

Once one of the child components called this.adminService.announceTickedMessage(this._tickedMessage);:

Child Component

import { Observable } from 'rxjs/Observable';
import { Component, ViewChild, OnInit, Inject } from '@angular/core';
import { AdminService } from '../../../core/admin/admin.service';

@Component({
  selector: 'cms',
  templateUrl: './thirdparty-cms.component.html',
  styleUrls: ['./thirdparty-cms.component.scss'],
})
export class ThirdPartyCmsComponent implements OnInit {
  private _tickedMessage: string;
  constructor(private adminService: AdminService) { }

  ngOnInit(): void {
    this._tickedMessage = 'Please do not create an entry for a page URL that does not exist in the CMS system';

    this.adminService.announceTickedMessage(this._tickedMessage);
  }
}

the parent component threw a ExpressionChangedAfterItHasBeenCheckedError exception because it tried updating one of its public properties with the ticked message value sent by the child component:

Parent Component(throws exception)

export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      On the side nav if you click on CMS System, this piece of code throws the exception: 
      "ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed 
       after it was checked. Previous value: 'false'. Current value: 'true'.""
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe((tickedMessage: string) => {
      this.tickedMessage = tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

What fixed the ExpressionChangedAfterItHasBeenCheckedError was by executing the subscribe call back asynchronously and awaiting the ticked message:

Parent Component(with async await)

export class AdminComponent implements OnInit, OnDestroy {
  private _tickedMessageSubscription: Subscription;

  tickedMessage: string = '';

  constructor(
    private router: Router,
    private adminService: AdminService
  ) { }

  ngOnInit() {
    /* 
      This clears the ExpressionChangedAfterItHasBeenCheckedError exception.
    */
    this._tickedMessageSubscription = this.adminService.tickedMessageAnnounced$.subscribe(async (tickedMessage: string) => {
      this.tickedMessage = await tickedMessage;
    });
  }

  ngOnDestroy() {
    this._tickedMessageSubscription.unsubscribe();
  }
}

Coming from the WPF world, it seems like we need to tell the UI thread to await the observable subscription callback since observables are being executed asynchronously?

I’m just starting out with Angular so please have some compassion towards my Angular skillz :P

@ktabarez Thanks, this helped me a lot!

@ktabarez Thanks! That seems to work nicely! I was wrapping the subscribe in the parent component in a timeout, which was also working, but felt dirty.

I am seeing that when interrogating the redux state its guaranteed to deliver but on startup like it when put in ngOnInit as opposed to constructors

@ktabarez Thanks a lot!

Your async ... await in subscribe solution works.

@ktabarez Your solution is essentially doing the same as a setTimeout({}, 0) but it feels more elegant. Quite like it! It also made me realize that anything can be awaited (pretty much like C# await Task.FromResult(tickedMessage)), so cheers for that!

So, question: why should we have to do an async/await on a calculation of a property on an observable that is getting data from the back end that might be changing frequently? What about ngClass makes this necessary? I get this while using an {observable | async} pipe. So the async/await isn't the best apprach for me. (or the async pipe isn't the best approach)

I have this issue where my parent component have multiple children components. One of the child component has an Input where it need a data from the parent component property and the property gets its data from a Observable/Promise (tried both) .

parent.component.html

<mat-tab-group>
   <mat-tab>
      <app-child-1></app-child-1>
   </mat-tab>
   <mat-tab>
      <app-child-2></app-child-2>
   </mat-tab>
   <mat-tab>
      <app-child-3 [datasource]="data"></app-child-3>
   </mat-tab>
</mat-tab-group>

parent.component.ts

// ... omitted...
data: any;

ngOnInit() {
   this.service1.getMethod(some_id).then(data => this.data = data);
}

I came across every solutions found in the thread. But nothing works in my case. Fortunately as some hinted that this is an issue due to manipulating a DOM, like putting an expression to _(ngIf)_ as example.

So in order to avoid this I try experimenting with ng-template, ng-container and ngTemplateOutlet.

<ng-container *ngTemplateOutlet="data ? content : loading"></ng-container>

<ng-template #content>
   <mat-tab-group>
      <mat-tab>
         <app-child-1></app-child-1>
      </mat-tab>
      <mat-tab>
         <app-child-2></app-child-2>
      </mat-tab>
      <mat-tab>
         <app-child-3 [datasource]="data"></app-child-3>
      </mat-tab>
   </mat-tab-group>
</ng-template>

<ng-template #loading>Loading your component. Please wait</ng-template>

I was able to solve this without using ChangeDetectorRef or setTimeout()

For me, this error occurred when showing / hiding field according to the condition, I was able to solve it after applying the values ​​of the fields setting:

this.form.get ('field').updateValueAndValidity();

I've been trying to do this with a mat-dialog that opens on init, and I have literally tried every solution I've seen on this thread (set timeout, promise resolve, observable pipe, after view init, after content init) and combinations therein. Still doesn't work. Then I saw @Splaktar post about how this violates one way data flow, so I literally made a flag in ngrx saying to open the dialog and subscribed to that, which is false initially and I'm still getting this error. What on earth do I do? Is there literally no way to open a modal dialog without attaching it to some completely separate event?

In on init:
this.store.pipe( select(getShouldLogin), ).subscribe((shouldLogin: boolean) => { if (shouldLogin) { this.openLoginDialog(); } }); this.checkUserId();

Auxiliary functions:
checkUserId() { const id = this.cookies.getUserId(); if (!id || id === 'undefined') { this.connApi.setShouldLogin(true); } }
openLoginDialog() { const dialogRef = this.dialog.open(LoginDialogComponent, { width: '400px', height: '300px', }); dialogRef.afterClosed().subscribe(result => this.handleLogin(result)); }

Using angular 6.0.0-rc.1

i'm using angular with ngrx and got this error after submitting a form.
fixed by setting
ChangeDetectionStrategy.OnPush
on form component

still having the issue. tried all sorts of workarounds. setTimeout works first time, but subsequent triggering of dialog.open result in the same error. Any status on this?

I am facing the same issue. Tried everything but it seems this issue arises on one way data flow.
Here I am trying to update selectedwoids. where the problem solves but the same error arises.

        <p-row> <p-column class="text-left" footer="{{selectedWoids.length}} {{getWoidString(selectedWoids.length)}} selected out of {{getTotalCounts()}} {{getWoidString(getTotalCounts())}}" colspan="11"></p-column> </p-row>

private setSelectedWoidsCount(){
if(this.isSelectAllWoids) {
this.selectedWoids = this.allWoids;
}
}

Because you break the rendering pipeline of Angular...

I'm seeing similar "ExpressionChanged..." errors after switching from 4.1.2 to 4.2.3.

In my case, I have two components that interact via a service. The service is provided via my main module, and ComponentA is created before ComponentB.

In 4.1.2, the following syntax worked just fine without errors:

_ComponentA Template:_

<ul *ngIf="myService.showList">
...

_ComponentB Class:_

ngOnInit() {
  this.myService.showList = false; //starts as true in the service
  ...
}

In 4.2.3, I have to modify ComponentA's template as follows to avoid the "ExpressionChanged..." error:

_ComponentA Template:_

<ul [hidden]="!myService.showList">
...

I'm still trying to figure out why this has only just become an issue, and why the switch from *ngIf to [hidden] works.

Did you find it how it worked when switching from ngIf to [hidden]

Is there a solution for this issue in Angular 6 yet ??

@alokkarma ... too old ... you should migrate it to Angular 6 or 5 at least. But your example code looks clear ... you are changing the service property in the child component B, and it affects some behavior in the child component A. Both children components are placed in the same parent, so all three are processed all together in relation in one CD cycle. What do you expect?

The fact that the same case was working in version 4.1.2 is related to some bugs which were eliminated in later versions, including 4.2.3.

I AM using Angular 6. I am using a MessageService to communicate between my authentication component and my app component to show different nav bar content if user is logged in (or not)

It works fine apart from this error!
I've tried other solutions such as EventEmitter but it doesn't work! or I get the same error.

@dotNetAthlete ... show a simple reproduction demo on Stackblitz. Talking about it without the real code is hard.

@dotNetAthlete I'm using the same basic mechanism where I have a state service that contains a page title as a behaviour subject (asObservable) in the main container component, and child components loaded into it which set the appropriate page title in the state service for the parent container to observe and display.

There was always an 'Expression changed' error when the container initialized the value and then the child component immediately updated it, so I do this now in the parent/container:

    this.stateSvc.currentPageTitle$
      .subscribe(
        (async (pageTitle) => {
          this.pageTitle = await pageTitle;
        }))

Where the state service has this:

  // Store
  private currentPageTitleStore = new BehaviorSubject<string>("");

  // Getter (as Observable)
  public currentPageTitle$ = this.currentPageTitleStore.asObservable();

  // Setter
  public setCurrentPageTitle(pageTitle: string) {
    this.currentPageTitleStore.next(pageTitle);
  }

This eliminates the issue. This solution is based on some helpful feedback from others in this thread.

@alignsoft - beautiful solution - issue fixed in Angular 6 app.

I am seeing this on page reload on angular 7 now ...
I am setting a child components value on parents ngAfterViewInit
Had to do this on the child component

  public activate() {
    setTimeout(() => this.active = true);
  }

I found the solution in this issue thread https://github.com/angular/angular/issues/10762
After I used the AfterContentInit life cycle hook, the error goes away.

@alignsoft , just adding to your change, since we are using a BehavioralSubject instead of a Subject,

I refined it as following:

\\ Component
export class AppComponent implements OnInit {
  isLoading: Boolean;

  constructor(private loaderService: LoaderService) { }

  ngOnInit(){
    this.loaderService.isLoading.subscribe(async data => {
      this.isLoading = await data;
    });
  }
}
\\ Service
@Injectable({
  providedIn: 'root'
})
export class LoaderService {
  // A BehaviorSubject is an Observable with a default value
  public isLoading: BehaviorSubject<Boolean> = new BehaviorSubject(false);
  constructor() {}
}
\\ Any other component or in my case, an interceptor that has the LoaderService injected
this.loaderService.isLoading.next(true);

But I agree with @daddyschmack , I would like to get any resource that points to info regarding withotu any of the above mentioned fixes (cdr.detectionChanges() or async await or aftercontentchecked), why [hidden] attribute works and not *ngIf

@acidghost Thank you for that link, it solved my problem. I actually had given up on trying to fix it in one area of my application but when it started happening again in a new area...

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings