ExpressionChangedAfterItHasBeenCheckedError Explained
Please explain to me why I keep getting this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Obviously, I only get it in dev mode, it doesn't happen on my production build, but it's very annoying and I simply don't understand the benefits of having an error in my dev environment that won't show up on prod --probably because of my lack of understanding.
Usually, the fix is easy enough, I just wrap the error causing code in a setTimeout like this:
setTimeout(()=>
this.isLoading = true;
, 0);
Or force detect changes with a constructor like this: constructor(private cd: ChangeDetectorRef)
:
this.isLoading = true;
this.cd.detectChanges();
But why do I constantly run into this error? I want to understand it so I can avoid these hacky fixes in the future.
angular angular2-changedetection angular2-databinding
add a comment |
Please explain to me why I keep getting this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Obviously, I only get it in dev mode, it doesn't happen on my production build, but it's very annoying and I simply don't understand the benefits of having an error in my dev environment that won't show up on prod --probably because of my lack of understanding.
Usually, the fix is easy enough, I just wrap the error causing code in a setTimeout like this:
setTimeout(()=>
this.isLoading = true;
, 0);
Or force detect changes with a constructor like this: constructor(private cd: ChangeDetectorRef)
:
this.isLoading = true;
this.cd.detectChanges();
But why do I constantly run into this error? I want to understand it so I can avoid these hacky fixes in the future.
angular angular2-changedetection angular2-databinding
5
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42
add a comment |
Please explain to me why I keep getting this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Obviously, I only get it in dev mode, it doesn't happen on my production build, but it's very annoying and I simply don't understand the benefits of having an error in my dev environment that won't show up on prod --probably because of my lack of understanding.
Usually, the fix is easy enough, I just wrap the error causing code in a setTimeout like this:
setTimeout(()=>
this.isLoading = true;
, 0);
Or force detect changes with a constructor like this: constructor(private cd: ChangeDetectorRef)
:
this.isLoading = true;
this.cd.detectChanges();
But why do I constantly run into this error? I want to understand it so I can avoid these hacky fixes in the future.
angular angular2-changedetection angular2-databinding
Please explain to me why I keep getting this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Obviously, I only get it in dev mode, it doesn't happen on my production build, but it's very annoying and I simply don't understand the benefits of having an error in my dev environment that won't show up on prod --probably because of my lack of understanding.
Usually, the fix is easy enough, I just wrap the error causing code in a setTimeout like this:
setTimeout(()=>
this.isLoading = true;
, 0);
Or force detect changes with a constructor like this: constructor(private cd: ChangeDetectorRef)
:
this.isLoading = true;
this.cd.detectChanges();
But why do I constantly run into this error? I want to understand it so I can avoid these hacky fixes in the future.
angular angular2-changedetection angular2-databinding
angular angular2-changedetection angular2-databinding
edited Sep 20 '18 at 5:10
Rohit Sharma
2,22521127
2,22521127
asked Apr 12 '17 at 16:59
Kevin LeStargeKevin LeStarge
1,5022922
1,5022922
5
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42
add a comment |
5
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42
5
5
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42
add a comment |
16 Answers
16
active
oldest
votes
I had a similar issue. Looking at the lifecycle hooks documentation, I changed ngAfterViewInit
to ngAfterContentInit
and it worked.
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property withsetTimeout
like you show above did the trick. Thanks!
– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
add a comment |
This error indicates a real problem in your application, therefore it makes sense to throw an exception.
In devMode
change detection adds an additional turn after every regular change detection run to check if the model has changed.
If the model has changed between the regular and the additional change detection turn, this indicates that either
- change detection itself has caused a change
- a method or getter returns a different value every time it is called
which are both bad, because it is not clear how to proceed because the model might never stabilize.
If Angular runs change detection until the model stabilizes, it might run forever.
If Angular doesn't run change detection, then the view might not reflect the current state of the model.
See also What is difference between production and development mode in Angular2?
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
Usually this is caused by some lifecycle callbacks likengOnInit
orngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how Ienable()
inside the getter:,get isUseMode() if (this._isUseMode) this.formGroup.enable()
I movedenable()
to the setter, and it works!
– The Red Pea
Apr 8 '18 at 18:16
1
It's not necessarily a problem with the app. The fact that callingchangeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside$scope.$watch()
in Angular 1.
– Man Personson
Nov 6 '18 at 18:52
|
show 1 more comment
A lot of understanding came once I understood the Angular Lifecycle Hooks and their relationship with change detection.
I was trying to get Angular to update a global flag bound to the *ngIf
of an element, and I was trying to change that flag inside of the ngOnInit()
life cycle hook of another component.
According to the documentation, this method is called after Angular has already detected changes:
Called once, after the first ngOnChanges().
So updating the flag inside of ngOnChanges()
won't initiate change detection. Then, once change detection has naturally triggered again, the flag's value has changed and the error is thrown.
In my case, I changed this:
constructor(private globalEventsService: GlobalEventsService)
ngOnInit()
this.globalEventsService.showCheckoutHeader = true;
To this:
constructor(private globalEventsService: GlobalEventsService)
this.globalEventsService.showCheckoutHeader = true;
ngOnInit()
and it fixed the problem :)
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
add a comment |
Update
I highly recommend starting with the OP's self response first: properly think about what can be done in the constructor
vs what should be done in ngOnChanges()
.
Original
This is more a side note than an answer, but it might help someone. I stumbled upon this problem when trying to make the presence of a button depend on the state of the form:
<button *ngIf="form.pristine">Yo</button>
As far as I know, this syntax leads to the button being added and removed from the DOM based on the condition. Which in turn leads to the ExpressionChangedAfterItHasBeenCheckedError
.
The fix in my case (although I don't claim to grasp the full implications of the difference), was to use display: none
instead:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
You might as well use[hidden]
instead of the very verbose[style.display]
part. :)
– Philipp Meissner
Jul 19 '18 at 5:33
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,[hidden]
will not always have the same behavior asdisplay: none
– Arnaud P
Aug 6 '18 at 6:49
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
add a comment |
In my case, I had this problem in my spec file, while running my tests.
I had to change ngIf
to [hidden]
<app-loading *ngIf="isLoading"></app-loading>
to
<app-loading [hidden]="!isLoading"></app-loading>
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2
– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
The difference here is that*ngIf
changes the DOM, adding and removing the element from the page, while[hidden]
changes the visibility of the item while not removing it from the DOM.
– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
add a comment |
Follow the below steps:
1.
Use 'ChangeDetectorRef' by importing it from @angular/core as follows:
import ChangeDetectorRef from '@angular/core';
2.
Implement it in constructor() as follows:
constructor( private cdRef : ChangeDetectorRef )
3.
Add the following method to your function which you are calling on an event like click of button. So it look like this:
functionName()
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
add a comment |
I was facing the same problem as value was changing in one of the array in my component. But instead of detecting the changes on value change, I changed the component change detection strategy to onPush
(which will detect changes on object change and not on value change).
import Component, OnInit, ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
)
add a comment |
Referring to the article https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
So the mechanics behind change detection actually works in a way that both change detection and verification digests are performed synchronously. That means, if we update properties asynchronously the values will not be updated when the verification loop is running and we will not get ExpressionChanged...
error. The reason we get this error is, during the verification process, Angular sees different values then what it recorded during change detection phase. So to avoid that....
1) Use changeDetectorRef
2) use setTimeOut. This will execute your code in another VM as a macro-task. Angular will not see these changes during verification process and you will not get that error.
setTimeout(() =>
this.isLoading = true;
);
3) If you really want to execute your code on same VM use like
Promise.resolve(null).then(() => this.isLoading = true);
This will create a micro-task. The micro-task queue is processed after the current synchronous code has finished executing hence the update to the property will happen after the verification step.
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
add a comment |
There were interesting answers but I didn't seem to find one to match my needs, the closest being from @chittrang-mishra which refers only to one specific function and not several toggles as in my app.
I did not want to use [hidden]
to take advantage of *ngIf
not even being a part of the DOM so I found the following solution which may not be the best for all as it suppresses the error instead of correcting it, but in my case where I know the final result is correct, it seems ok for my app.
What I did was implement AfterViewChecked
, add constructor(private changeDetector : ChangeDetectorRef )
and then
ngAfterViewChecked()
this.changeDetector.detectChanges();
I hope this helps other as many others have helped me.
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
add a comment |
Angular runs change detection and when its find that some values which has been passed to the child component has been changed Angular throws the error ExpressionChangedAfterItHasBeenCheckedError click for More
In order to Correct this we can use the AfterContentChecked life cycle hook and
import ChangeDetectorRef, AfterContentChecked from '@angular/core';
constructor(
private cdref: ChangeDetectorRef)
ngAfterContentChecked()
this.cdref.detectChanges();
add a comment |
I had this sort of error in Ionic3 (which uses Angular 4 as part of it's technology stack).
For me it was doing this:
<ion-icon [name]="getFavIconName()"></ion-icon>
So I was trying to conditionally change the type of an ion-icon from a pin
to a remove-circle
, per a mode a screen was operating on.
I'm guessing I'll have to add an *ngIF instead.
add a comment |
For my issue, I was reading github - "ExpressionChangedAfterItHasBeenCheckedError when changing a component 'non model' value in afterViewInit" and decided to add the ngModel
<input type="hidden" ngModel #clientName />
It fixed my issue, I hope it helps someone.
1
Where on that site does it say to addngModel
. And could you please elaborate why this should be helpful?
– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
add a comment |
Here's my thoughts on what is happening. I have not read the documentation but am sure this is part of why the error is shown.
*ngIf="isProcessing()"
When using *ngIf, it physically changes the DOM by adding or removing the element every time the condition changes. So if the condition changes before it is rendered to the view (which is highly possible in Angular's world), the error is thrown. See explanation here between development and production modes.
[hidden]="isProcessing()"
When using [hidden] it does not physically change the DOM but merely hiding the element from the view, most likely using CSS in the back. The element is still there in the DOM but not visible depending on the condition's value. That is why the error will not occur when using [hidden].
add a comment |
My issue was manifest when I added *ngIf
but that wasn't the cause. The error was caused by changing the model in tags then trying to display the changed model in the
*ngIf
statement later on. Here's an example:
<div>changeMyModelValue()</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">myModel.value</div>
To fix the issue, I changed where I called changeMyModelValue() to a place that made more sense.
In my situation I wanted changeMyModelValue() called whenever a child component changed the data. This required I create and emit an event in the child component so the parent could handle it (by calling changeMyModelValue(). see https://angular.io/guide/component-interaction#parent-listens-for-child-event
add a comment |
@HostBinding
can be a confusing source of this error.
For example, lets say you have the following host binding in a component
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
For simplicity, lets say this property is updated via the following input property:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
this.style_groupBG = carouselConfig.bgColor;
In the parent component you are programatically setting it in ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
this.carousel.carouselConfig = bgColor: 'red' ;
Here's what happens :
- Your parent component is created
- The ImageCarousel component is created, and assigned to
carousel
(via ViewChild) - We can't access
carousel
untilngAfterViewInit()
(it will be null) - We assign the configuration, which sets
style_groupBG = 'red'
- This in turn sets
background: red
on the host ImageCarousel component - This component is 'owned' by your parent component, so when it checks for changes it finds a change on
carousel.style.background
and isn't clever enough to know that this isn't a problem so it throws the exception.
One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding
(such as allowing the parent to control the full bounds of the object).
The better solution, in the parent component is to add detectChanges() after setting the config.
ngAfterViewInit()
this.carousel.carouselConfig = ... ;
this.cdr.detectChanges();
This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.
Consider the case where you don't add @HostBinding
until later during development. Suddenly you get this error and it doesn't seem to make any sense.
add a comment |
Debugging tips
This error can be quite confusing, and it's easy to make a wrong assumption about exactly when it's occuring. I find it helpful to add a lot of debugging statements like this throughout the affected components in the appropriate places. This helps understand the flow.
In the parent put statements like this (the exact string 'EXPRESSIONCHANGED' is important), but other than that these are just examples:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / timer callbacks:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
If you run detectChanges
manually add logging for that too:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Then in Chrome debugger just filter by 'EXPRESSIONCHANGES'. This will show you exactly the flow and order of everything that gets set, and also exactly at what point Angular throws the error.
You can also click on the gray links to put breakpoints in.
Another thing to watch out if you have similarly named properties throughout your application (such as style.background
) make sure you're debugging the one you think you - by setting it to an obscure color value.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43375532%2fexpressionchangedafterithasbeencheckederror-explained%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
16 Answers
16
active
oldest
votes
16 Answers
16
active
oldest
votes
active
oldest
votes
active
oldest
votes
I had a similar issue. Looking at the lifecycle hooks documentation, I changed ngAfterViewInit
to ngAfterContentInit
and it worked.
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property withsetTimeout
like you show above did the trick. Thanks!
– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
add a comment |
I had a similar issue. Looking at the lifecycle hooks documentation, I changed ngAfterViewInit
to ngAfterContentInit
and it worked.
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property withsetTimeout
like you show above did the trick. Thanks!
– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
add a comment |
I had a similar issue. Looking at the lifecycle hooks documentation, I changed ngAfterViewInit
to ngAfterContentInit
and it worked.
I had a similar issue. Looking at the lifecycle hooks documentation, I changed ngAfterViewInit
to ngAfterContentInit
and it worked.
edited Mar 22 '18 at 4:24
rrrafalsz
157114
157114
answered Jul 27 '17 at 3:57
onlymeonlyme
1,11611010
1,11611010
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property withsetTimeout
like you show above did the trick. Thanks!
– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
add a comment |
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property withsetTimeout
like you show above did the trick. Thanks!
– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property with
setTimeout
like you show above did the trick. Thanks!– kbpontius
Feb 1 '18 at 22:11
@PhilipEnc my issue was related to a change triggered by the DOM changing. When the DOM would change, the QueryList object (that came from a @ContentChildren property) would update, and inside the method that the update called it changed the two-way bound property. This created the problem I was having. Wrapping that change to the two-property with
setTimeout
like you show above did the trick. Thanks!– kbpontius
Feb 1 '18 at 22:11
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
In my case I had placed some code that changed the value of primeng grid array in ngAfterContentInit , I placed the code in ngOnInit and it worked.
– Vibhu
Oct 18 '18 at 13:15
add a comment |
This error indicates a real problem in your application, therefore it makes sense to throw an exception.
In devMode
change detection adds an additional turn after every regular change detection run to check if the model has changed.
If the model has changed between the regular and the additional change detection turn, this indicates that either
- change detection itself has caused a change
- a method or getter returns a different value every time it is called
which are both bad, because it is not clear how to proceed because the model might never stabilize.
If Angular runs change detection until the model stabilizes, it might run forever.
If Angular doesn't run change detection, then the view might not reflect the current state of the model.
See also What is difference between production and development mode in Angular2?
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
Usually this is caused by some lifecycle callbacks likengOnInit
orngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how Ienable()
inside the getter:,get isUseMode() if (this._isUseMode) this.formGroup.enable()
I movedenable()
to the setter, and it works!
– The Red Pea
Apr 8 '18 at 18:16
1
It's not necessarily a problem with the app. The fact that callingchangeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside$scope.$watch()
in Angular 1.
– Man Personson
Nov 6 '18 at 18:52
|
show 1 more comment
This error indicates a real problem in your application, therefore it makes sense to throw an exception.
In devMode
change detection adds an additional turn after every regular change detection run to check if the model has changed.
If the model has changed between the regular and the additional change detection turn, this indicates that either
- change detection itself has caused a change
- a method or getter returns a different value every time it is called
which are both bad, because it is not clear how to proceed because the model might never stabilize.
If Angular runs change detection until the model stabilizes, it might run forever.
If Angular doesn't run change detection, then the view might not reflect the current state of the model.
See also What is difference between production and development mode in Angular2?
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
Usually this is caused by some lifecycle callbacks likengOnInit
orngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how Ienable()
inside the getter:,get isUseMode() if (this._isUseMode) this.formGroup.enable()
I movedenable()
to the setter, and it works!
– The Red Pea
Apr 8 '18 at 18:16
1
It's not necessarily a problem with the app. The fact that callingchangeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside$scope.$watch()
in Angular 1.
– Man Personson
Nov 6 '18 at 18:52
|
show 1 more comment
This error indicates a real problem in your application, therefore it makes sense to throw an exception.
In devMode
change detection adds an additional turn after every regular change detection run to check if the model has changed.
If the model has changed between the regular and the additional change detection turn, this indicates that either
- change detection itself has caused a change
- a method or getter returns a different value every time it is called
which are both bad, because it is not clear how to proceed because the model might never stabilize.
If Angular runs change detection until the model stabilizes, it might run forever.
If Angular doesn't run change detection, then the view might not reflect the current state of the model.
See also What is difference between production and development mode in Angular2?
This error indicates a real problem in your application, therefore it makes sense to throw an exception.
In devMode
change detection adds an additional turn after every regular change detection run to check if the model has changed.
If the model has changed between the regular and the additional change detection turn, this indicates that either
- change detection itself has caused a change
- a method or getter returns a different value every time it is called
which are both bad, because it is not clear how to proceed because the model might never stabilize.
If Angular runs change detection until the model stabilizes, it might run forever.
If Angular doesn't run change detection, then the view might not reflect the current state of the model.
See also What is difference between production and development mode in Angular2?
edited May 23 '17 at 11:47
Community♦
11
11
answered Apr 12 '17 at 17:03
Günter ZöchbauerGünter Zöchbauer
324k69968904
324k69968904
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
Usually this is caused by some lifecycle callbacks likengOnInit
orngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how Ienable()
inside the getter:,get isUseMode() if (this._isUseMode) this.formGroup.enable()
I movedenable()
to the setter, and it works!
– The Red Pea
Apr 8 '18 at 18:16
1
It's not necessarily a problem with the app. The fact that callingchangeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside$scope.$watch()
in Angular 1.
– Man Personson
Nov 6 '18 at 18:52
|
show 1 more comment
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
Usually this is caused by some lifecycle callbacks likengOnInit
orngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how Ienable()
inside the getter:,get isUseMode() if (this._isUseMode) this.formGroup.enable()
I movedenable()
to the setter, and it works!
– The Red Pea
Apr 8 '18 at 18:16
1
It's not necessarily a problem with the app. The fact that callingchangeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside$scope.$watch()
in Angular 1.
– Man Personson
Nov 6 '18 at 18:52
4
4
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
How can I avoid seeing this error in the future? Is there a different way I need to be thinking about my code to ensure I do not make the same mistakes?
– Kevin LeStarge
Apr 13 '17 at 16:39
14
14
Usually this is caused by some lifecycle callbacks like
ngOnInit
or ngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.– Günter Zöchbauer
Apr 13 '17 at 16:42
Usually this is caused by some lifecycle callbacks like
ngOnInit
or ngOnChanges
to modify the model (some lifecycle callbacks allow modify the model others don't, I don't remember myself exactly which one do or do not). Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.– Günter Zöchbauer
Apr 13 '17 at 16:42
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
For anyone arriving here who gets this error using ngx-toaster library, here is the bug report: github.com/scttcper/ngx-toastr/issues/160
– rmcsharry
Sep 24 '17 at 15:32
In my case I modified the model inside a Typescript 'getter'; notice how I
enable()
inside the getter:, get isUseMode() if (this._isUseMode) this.formGroup.enable()
I moved enable()
to the setter, and it works!– The Red Pea
Apr 8 '18 at 18:16
In my case I modified the model inside a Typescript 'getter'; notice how I
enable()
inside the getter:, get isUseMode() if (this._isUseMode) this.formGroup.enable()
I moved enable()
to the setter, and it works!– The Red Pea
Apr 8 '18 at 18:16
1
1
It's not necessarily a problem with the app. The fact that calling
changeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside $scope.$watch()
in Angular 1.– Man Personson
Nov 6 '18 at 18:52
It's not necessarily a problem with the app. The fact that calling
changeRef.detectChanges()
is a solution / suppresses the error, is proof of this. It's like modifying state inside $scope.$watch()
in Angular 1.– Man Personson
Nov 6 '18 at 18:52
|
show 1 more comment
A lot of understanding came once I understood the Angular Lifecycle Hooks and their relationship with change detection.
I was trying to get Angular to update a global flag bound to the *ngIf
of an element, and I was trying to change that flag inside of the ngOnInit()
life cycle hook of another component.
According to the documentation, this method is called after Angular has already detected changes:
Called once, after the first ngOnChanges().
So updating the flag inside of ngOnChanges()
won't initiate change detection. Then, once change detection has naturally triggered again, the flag's value has changed and the error is thrown.
In my case, I changed this:
constructor(private globalEventsService: GlobalEventsService)
ngOnInit()
this.globalEventsService.showCheckoutHeader = true;
To this:
constructor(private globalEventsService: GlobalEventsService)
this.globalEventsService.showCheckoutHeader = true;
ngOnInit()
and it fixed the problem :)
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
add a comment |
A lot of understanding came once I understood the Angular Lifecycle Hooks and their relationship with change detection.
I was trying to get Angular to update a global flag bound to the *ngIf
of an element, and I was trying to change that flag inside of the ngOnInit()
life cycle hook of another component.
According to the documentation, this method is called after Angular has already detected changes:
Called once, after the first ngOnChanges().
So updating the flag inside of ngOnChanges()
won't initiate change detection. Then, once change detection has naturally triggered again, the flag's value has changed and the error is thrown.
In my case, I changed this:
constructor(private globalEventsService: GlobalEventsService)
ngOnInit()
this.globalEventsService.showCheckoutHeader = true;
To this:
constructor(private globalEventsService: GlobalEventsService)
this.globalEventsService.showCheckoutHeader = true;
ngOnInit()
and it fixed the problem :)
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
add a comment |
A lot of understanding came once I understood the Angular Lifecycle Hooks and their relationship with change detection.
I was trying to get Angular to update a global flag bound to the *ngIf
of an element, and I was trying to change that flag inside of the ngOnInit()
life cycle hook of another component.
According to the documentation, this method is called after Angular has already detected changes:
Called once, after the first ngOnChanges().
So updating the flag inside of ngOnChanges()
won't initiate change detection. Then, once change detection has naturally triggered again, the flag's value has changed and the error is thrown.
In my case, I changed this:
constructor(private globalEventsService: GlobalEventsService)
ngOnInit()
this.globalEventsService.showCheckoutHeader = true;
To this:
constructor(private globalEventsService: GlobalEventsService)
this.globalEventsService.showCheckoutHeader = true;
ngOnInit()
and it fixed the problem :)
A lot of understanding came once I understood the Angular Lifecycle Hooks and their relationship with change detection.
I was trying to get Angular to update a global flag bound to the *ngIf
of an element, and I was trying to change that flag inside of the ngOnInit()
life cycle hook of another component.
According to the documentation, this method is called after Angular has already detected changes:
Called once, after the first ngOnChanges().
So updating the flag inside of ngOnChanges()
won't initiate change detection. Then, once change detection has naturally triggered again, the flag's value has changed and the error is thrown.
In my case, I changed this:
constructor(private globalEventsService: GlobalEventsService)
ngOnInit()
this.globalEventsService.showCheckoutHeader = true;
To this:
constructor(private globalEventsService: GlobalEventsService)
this.globalEventsService.showCheckoutHeader = true;
ngOnInit()
and it fixed the problem :)
answered Jan 11 '18 at 21:52
Kevin LeStargeKevin LeStarge
1,5022922
1,5022922
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
add a comment |
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
1
1
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
My problem was similar. That I did a mistake after long hours, and defined a variable outside the ngOnInit function and constructor. This receives data changes from an observable, which is placed in the initalization function. Did the same thing as you to fix the error.
– ravo10
2 days ago
add a comment |
Update
I highly recommend starting with the OP's self response first: properly think about what can be done in the constructor
vs what should be done in ngOnChanges()
.
Original
This is more a side note than an answer, but it might help someone. I stumbled upon this problem when trying to make the presence of a button depend on the state of the form:
<button *ngIf="form.pristine">Yo</button>
As far as I know, this syntax leads to the button being added and removed from the DOM based on the condition. Which in turn leads to the ExpressionChangedAfterItHasBeenCheckedError
.
The fix in my case (although I don't claim to grasp the full implications of the difference), was to use display: none
instead:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
You might as well use[hidden]
instead of the very verbose[style.display]
part. :)
– Philipp Meissner
Jul 19 '18 at 5:33
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,[hidden]
will not always have the same behavior asdisplay: none
– Arnaud P
Aug 6 '18 at 6:49
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
add a comment |
Update
I highly recommend starting with the OP's self response first: properly think about what can be done in the constructor
vs what should be done in ngOnChanges()
.
Original
This is more a side note than an answer, but it might help someone. I stumbled upon this problem when trying to make the presence of a button depend on the state of the form:
<button *ngIf="form.pristine">Yo</button>
As far as I know, this syntax leads to the button being added and removed from the DOM based on the condition. Which in turn leads to the ExpressionChangedAfterItHasBeenCheckedError
.
The fix in my case (although I don't claim to grasp the full implications of the difference), was to use display: none
instead:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
You might as well use[hidden]
instead of the very verbose[style.display]
part. :)
– Philipp Meissner
Jul 19 '18 at 5:33
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,[hidden]
will not always have the same behavior asdisplay: none
– Arnaud P
Aug 6 '18 at 6:49
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
add a comment |
Update
I highly recommend starting with the OP's self response first: properly think about what can be done in the constructor
vs what should be done in ngOnChanges()
.
Original
This is more a side note than an answer, but it might help someone. I stumbled upon this problem when trying to make the presence of a button depend on the state of the form:
<button *ngIf="form.pristine">Yo</button>
As far as I know, this syntax leads to the button being added and removed from the DOM based on the condition. Which in turn leads to the ExpressionChangedAfterItHasBeenCheckedError
.
The fix in my case (although I don't claim to grasp the full implications of the difference), was to use display: none
instead:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
Update
I highly recommend starting with the OP's self response first: properly think about what can be done in the constructor
vs what should be done in ngOnChanges()
.
Original
This is more a side note than an answer, but it might help someone. I stumbled upon this problem when trying to make the presence of a button depend on the state of the form:
<button *ngIf="form.pristine">Yo</button>
As far as I know, this syntax leads to the button being added and removed from the DOM based on the condition. Which in turn leads to the ExpressionChangedAfterItHasBeenCheckedError
.
The fix in my case (although I don't claim to grasp the full implications of the difference), was to use display: none
instead:
<button [style.display]="form.pristine ? 'inline' : 'none'">Yo</button>
edited Oct 8 '18 at 12:54
answered Jun 1 '17 at 7:06
Arnaud PArnaud P
6,13622943
6,13622943
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
You might as well use[hidden]
instead of the very verbose[style.display]
part. :)
– Philipp Meissner
Jul 19 '18 at 5:33
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,[hidden]
will not always have the same behavior asdisplay: none
– Arnaud P
Aug 6 '18 at 6:49
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
add a comment |
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
You might as well use[hidden]
instead of the very verbose[style.display]
part. :)
– Philipp Meissner
Jul 19 '18 at 5:33
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,[hidden]
will not always have the same behavior asdisplay: none
– Arnaud P
Aug 6 '18 at 6:49
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
5
5
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
My understanding of the difference between the ngIf vs. the style is that the ngIf does not include the HTML in the page until the condition is true, thus reducing the "page weight" a tiny bit while the style technique causes the HTML to always be in the page and is simply hidden or shown based on the value of form.pristine.
– user3785010
Jul 3 '17 at 14:40
2
2
You might as well use
[hidden]
instead of the very verbose [style.display]
part. :)– Philipp Meissner
Jul 19 '18 at 5:33
You might as well use
[hidden]
instead of the very verbose [style.display]
part. :)– Philipp Meissner
Jul 19 '18 at 5:33
1
1
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,
[hidden]
will not always have the same behavior as display: none
– Arnaud P
Aug 6 '18 at 6:49
Why not. Although, as mentioned by @Simon_Weaver in another comment on this page,
[hidden]
will not always have the same behavior as display: none
– Arnaud P
Aug 6 '18 at 6:49
1
1
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
I was showing two different buttons (logout/ login) with *ngIf in each button and this was causing the problem.
– GoTo
Oct 7 '18 at 8:20
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
constructor was the right place for me, launching a material snack-bar
– austin
Nov 26 '18 at 22:32
add a comment |
In my case, I had this problem in my spec file, while running my tests.
I had to change ngIf
to [hidden]
<app-loading *ngIf="isLoading"></app-loading>
to
<app-loading [hidden]="!isLoading"></app-loading>
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2
– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
The difference here is that*ngIf
changes the DOM, adding and removing the element from the page, while[hidden]
changes the visibility of the item while not removing it from the DOM.
– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
add a comment |
In my case, I had this problem in my spec file, while running my tests.
I had to change ngIf
to [hidden]
<app-loading *ngIf="isLoading"></app-loading>
to
<app-loading [hidden]="!isLoading"></app-loading>
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2
– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
The difference here is that*ngIf
changes the DOM, adding and removing the element from the page, while[hidden]
changes the visibility of the item while not removing it from the DOM.
– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
add a comment |
In my case, I had this problem in my spec file, while running my tests.
I had to change ngIf
to [hidden]
<app-loading *ngIf="isLoading"></app-loading>
to
<app-loading [hidden]="!isLoading"></app-loading>
In my case, I had this problem in my spec file, while running my tests.
I had to change ngIf
to [hidden]
<app-loading *ngIf="isLoading"></app-loading>
to
<app-loading [hidden]="!isLoading"></app-loading>
edited May 10 '18 at 21:48
Michael
3,54134058
3,54134058
answered Feb 22 '18 at 19:52
Andre EvangelistaAndre Evangelista
1,0971210
1,0971210
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2
– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
The difference here is that*ngIf
changes the DOM, adding and removing the element from the page, while[hidden]
changes the visibility of the item while not removing it from the DOM.
– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
add a comment |
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2
– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
The difference here is that*ngIf
changes the DOM, adding and removing the element from the page, while[hidden]
changes the visibility of the item while not removing it from the DOM.
– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
3
3
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
This works ... weird but why doesn't the ngIf directive work .... (?)
– Stefan Zvonar
Jun 15 '18 at 7:36
About
[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2– Simon_Weaver
Aug 2 '18 at 19:44
About
[hidden]
: talkingdotnet.com/dont-use-hidden-attribute-angularjs-2– Simon_Weaver
Aug 2 '18 at 19:44
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
is this cause performance issue?
– Hemanth SP
Oct 3 '18 at 13:27
1
1
The difference here is that
*ngIf
changes the DOM, adding and removing the element from the page, while [hidden]
changes the visibility of the item while not removing it from the DOM.– Grungondola
Oct 30 '18 at 11:08
The difference here is that
*ngIf
changes the DOM, adding and removing the element from the page, while [hidden]
changes the visibility of the item while not removing it from the DOM.– Grungondola
Oct 30 '18 at 11:08
But, this didn't really fix the real problem...?
– ravo10
2 days ago
But, this didn't really fix the real problem...?
– ravo10
2 days ago
add a comment |
Follow the below steps:
1.
Use 'ChangeDetectorRef' by importing it from @angular/core as follows:
import ChangeDetectorRef from '@angular/core';
2.
Implement it in constructor() as follows:
constructor( private cdRef : ChangeDetectorRef )
3.
Add the following method to your function which you are calling on an event like click of button. So it look like this:
functionName()
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
add a comment |
Follow the below steps:
1.
Use 'ChangeDetectorRef' by importing it from @angular/core as follows:
import ChangeDetectorRef from '@angular/core';
2.
Implement it in constructor() as follows:
constructor( private cdRef : ChangeDetectorRef )
3.
Add the following method to your function which you are calling on an event like click of button. So it look like this:
functionName()
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
add a comment |
Follow the below steps:
1.
Use 'ChangeDetectorRef' by importing it from @angular/core as follows:
import ChangeDetectorRef from '@angular/core';
2.
Implement it in constructor() as follows:
constructor( private cdRef : ChangeDetectorRef )
3.
Add the following method to your function which you are calling on an event like click of button. So it look like this:
functionName()
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
Follow the below steps:
1.
Use 'ChangeDetectorRef' by importing it from @angular/core as follows:
import ChangeDetectorRef from '@angular/core';
2.
Implement it in constructor() as follows:
constructor( private cdRef : ChangeDetectorRef )
3.
Add the following method to your function which you are calling on an event like click of button. So it look like this:
functionName()
yourCode;
//add this line to get rid of the error
this.cdRef.detectChanges();
edited May 1 '18 at 12:08
Tom
1,59711120
1,59711120
answered May 1 '18 at 10:27
Chittrang MishraChittrang Mishra
13112
13112
add a comment |
add a comment |
I was facing the same problem as value was changing in one of the array in my component. But instead of detecting the changes on value change, I changed the component change detection strategy to onPush
(which will detect changes on object change and not on value change).
import Component, OnInit, ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
)
add a comment |
I was facing the same problem as value was changing in one of the array in my component. But instead of detecting the changes on value change, I changed the component change detection strategy to onPush
(which will detect changes on object change and not on value change).
import Component, OnInit, ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
)
add a comment |
I was facing the same problem as value was changing in one of the array in my component. But instead of detecting the changes on value change, I changed the component change detection strategy to onPush
(which will detect changes on object change and not on value change).
import Component, OnInit, ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
)
I was facing the same problem as value was changing in one of the array in my component. But instead of detecting the changes on value change, I changed the component change detection strategy to onPush
(which will detect changes on object change and not on value change).
import Component, OnInit, ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush
selector: -
......
)
edited May 12 '18 at 22:40
Massimiliano Kraus
2,36941632
2,36941632
answered Jan 9 '18 at 7:39
Dheeraj Dheeraj
9112
9112
add a comment |
add a comment |
Referring to the article https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
So the mechanics behind change detection actually works in a way that both change detection and verification digests are performed synchronously. That means, if we update properties asynchronously the values will not be updated when the verification loop is running and we will not get ExpressionChanged...
error. The reason we get this error is, during the verification process, Angular sees different values then what it recorded during change detection phase. So to avoid that....
1) Use changeDetectorRef
2) use setTimeOut. This will execute your code in another VM as a macro-task. Angular will not see these changes during verification process and you will not get that error.
setTimeout(() =>
this.isLoading = true;
);
3) If you really want to execute your code on same VM use like
Promise.resolve(null).then(() => this.isLoading = true);
This will create a micro-task. The micro-task queue is processed after the current synchronous code has finished executing hence the update to the property will happen after the verification step.
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
add a comment |
Referring to the article https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
So the mechanics behind change detection actually works in a way that both change detection and verification digests are performed synchronously. That means, if we update properties asynchronously the values will not be updated when the verification loop is running and we will not get ExpressionChanged...
error. The reason we get this error is, during the verification process, Angular sees different values then what it recorded during change detection phase. So to avoid that....
1) Use changeDetectorRef
2) use setTimeOut. This will execute your code in another VM as a macro-task. Angular will not see these changes during verification process and you will not get that error.
setTimeout(() =>
this.isLoading = true;
);
3) If you really want to execute your code on same VM use like
Promise.resolve(null).then(() => this.isLoading = true);
This will create a micro-task. The micro-task queue is processed after the current synchronous code has finished executing hence the update to the property will happen after the verification step.
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
add a comment |
Referring to the article https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
So the mechanics behind change detection actually works in a way that both change detection and verification digests are performed synchronously. That means, if we update properties asynchronously the values will not be updated when the verification loop is running and we will not get ExpressionChanged...
error. The reason we get this error is, during the verification process, Angular sees different values then what it recorded during change detection phase. So to avoid that....
1) Use changeDetectorRef
2) use setTimeOut. This will execute your code in another VM as a macro-task. Angular will not see these changes during verification process and you will not get that error.
setTimeout(() =>
this.isLoading = true;
);
3) If you really want to execute your code on same VM use like
Promise.resolve(null).then(() => this.isLoading = true);
This will create a micro-task. The micro-task queue is processed after the current synchronous code has finished executing hence the update to the property will happen after the verification step.
Referring to the article https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4
So the mechanics behind change detection actually works in a way that both change detection and verification digests are performed synchronously. That means, if we update properties asynchronously the values will not be updated when the verification loop is running and we will not get ExpressionChanged...
error. The reason we get this error is, during the verification process, Angular sees different values then what it recorded during change detection phase. So to avoid that....
1) Use changeDetectorRef
2) use setTimeOut. This will execute your code in another VM as a macro-task. Angular will not see these changes during verification process and you will not get that error.
setTimeout(() =>
this.isLoading = true;
);
3) If you really want to execute your code on same VM use like
Promise.resolve(null).then(() => this.isLoading = true);
This will create a micro-task. The micro-task queue is processed after the current synchronous code has finished executing hence the update to the property will happen after the verification step.
answered Jun 12 '18 at 21:55
ATHERATHER
1,22241942
1,22241942
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
add a comment |
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
Can you use option #3 with a style expression? I have a style expression for height that should be evaluated last, because it is based on injected content.
– N-ate
Aug 2 '18 at 23:38
1
1
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
Sorry just saw your comment, yea i dont see any reason why not. So that should work with style changes as well.
– ATHER
Sep 30 '18 at 21:04
add a comment |
There were interesting answers but I didn't seem to find one to match my needs, the closest being from @chittrang-mishra which refers only to one specific function and not several toggles as in my app.
I did not want to use [hidden]
to take advantage of *ngIf
not even being a part of the DOM so I found the following solution which may not be the best for all as it suppresses the error instead of correcting it, but in my case where I know the final result is correct, it seems ok for my app.
What I did was implement AfterViewChecked
, add constructor(private changeDetector : ChangeDetectorRef )
and then
ngAfterViewChecked()
this.changeDetector.detectChanges();
I hope this helps other as many others have helped me.
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
add a comment |
There were interesting answers but I didn't seem to find one to match my needs, the closest being from @chittrang-mishra which refers only to one specific function and not several toggles as in my app.
I did not want to use [hidden]
to take advantage of *ngIf
not even being a part of the DOM so I found the following solution which may not be the best for all as it suppresses the error instead of correcting it, but in my case where I know the final result is correct, it seems ok for my app.
What I did was implement AfterViewChecked
, add constructor(private changeDetector : ChangeDetectorRef )
and then
ngAfterViewChecked()
this.changeDetector.detectChanges();
I hope this helps other as many others have helped me.
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
add a comment |
There were interesting answers but I didn't seem to find one to match my needs, the closest being from @chittrang-mishra which refers only to one specific function and not several toggles as in my app.
I did not want to use [hidden]
to take advantage of *ngIf
not even being a part of the DOM so I found the following solution which may not be the best for all as it suppresses the error instead of correcting it, but in my case where I know the final result is correct, it seems ok for my app.
What I did was implement AfterViewChecked
, add constructor(private changeDetector : ChangeDetectorRef )
and then
ngAfterViewChecked()
this.changeDetector.detectChanges();
I hope this helps other as many others have helped me.
There were interesting answers but I didn't seem to find one to match my needs, the closest being from @chittrang-mishra which refers only to one specific function and not several toggles as in my app.
I did not want to use [hidden]
to take advantage of *ngIf
not even being a part of the DOM so I found the following solution which may not be the best for all as it suppresses the error instead of correcting it, but in my case where I know the final result is correct, it seems ok for my app.
What I did was implement AfterViewChecked
, add constructor(private changeDetector : ChangeDetectorRef )
and then
ngAfterViewChecked()
this.changeDetector.detectChanges();
I hope this helps other as many others have helped me.
answered Oct 18 '18 at 1:17
epereper
8114
8114
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
add a comment |
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
Same for me ! Thank you
– Christophe Chevalier
Jan 14 at 16:42
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
won't this trigger an infinite change detection loop? i mean, you are detecting for changes after you checked.
– Manuel Azar
Feb 7 at 19:18
add a comment |
Angular runs change detection and when its find that some values which has been passed to the child component has been changed Angular throws the error ExpressionChangedAfterItHasBeenCheckedError click for More
In order to Correct this we can use the AfterContentChecked life cycle hook and
import ChangeDetectorRef, AfterContentChecked from '@angular/core';
constructor(
private cdref: ChangeDetectorRef)
ngAfterContentChecked()
this.cdref.detectChanges();
add a comment |
Angular runs change detection and when its find that some values which has been passed to the child component has been changed Angular throws the error ExpressionChangedAfterItHasBeenCheckedError click for More
In order to Correct this we can use the AfterContentChecked life cycle hook and
import ChangeDetectorRef, AfterContentChecked from '@angular/core';
constructor(
private cdref: ChangeDetectorRef)
ngAfterContentChecked()
this.cdref.detectChanges();
add a comment |
Angular runs change detection and when its find that some values which has been passed to the child component has been changed Angular throws the error ExpressionChangedAfterItHasBeenCheckedError click for More
In order to Correct this we can use the AfterContentChecked life cycle hook and
import ChangeDetectorRef, AfterContentChecked from '@angular/core';
constructor(
private cdref: ChangeDetectorRef)
ngAfterContentChecked()
this.cdref.detectChanges();
Angular runs change detection and when its find that some values which has been passed to the child component has been changed Angular throws the error ExpressionChangedAfterItHasBeenCheckedError click for More
In order to Correct this we can use the AfterContentChecked life cycle hook and
import ChangeDetectorRef, AfterContentChecked from '@angular/core';
constructor(
private cdref: ChangeDetectorRef)
ngAfterContentChecked()
this.cdref.detectChanges();
answered Nov 8 '18 at 14:43
LijoLijo
2,39112642
2,39112642
add a comment |
add a comment |
I had this sort of error in Ionic3 (which uses Angular 4 as part of it's technology stack).
For me it was doing this:
<ion-icon [name]="getFavIconName()"></ion-icon>
So I was trying to conditionally change the type of an ion-icon from a pin
to a remove-circle
, per a mode a screen was operating on.
I'm guessing I'll have to add an *ngIF instead.
add a comment |
I had this sort of error in Ionic3 (which uses Angular 4 as part of it's technology stack).
For me it was doing this:
<ion-icon [name]="getFavIconName()"></ion-icon>
So I was trying to conditionally change the type of an ion-icon from a pin
to a remove-circle
, per a mode a screen was operating on.
I'm guessing I'll have to add an *ngIF instead.
add a comment |
I had this sort of error in Ionic3 (which uses Angular 4 as part of it's technology stack).
For me it was doing this:
<ion-icon [name]="getFavIconName()"></ion-icon>
So I was trying to conditionally change the type of an ion-icon from a pin
to a remove-circle
, per a mode a screen was operating on.
I'm guessing I'll have to add an *ngIF instead.
I had this sort of error in Ionic3 (which uses Angular 4 as part of it's technology stack).
For me it was doing this:
<ion-icon [name]="getFavIconName()"></ion-icon>
So I was trying to conditionally change the type of an ion-icon from a pin
to a remove-circle
, per a mode a screen was operating on.
I'm guessing I'll have to add an *ngIF instead.
answered Oct 18 '17 at 17:58
JGFMKJGFMK
3,32243057
3,32243057
add a comment |
add a comment |
For my issue, I was reading github - "ExpressionChangedAfterItHasBeenCheckedError when changing a component 'non model' value in afterViewInit" and decided to add the ngModel
<input type="hidden" ngModel #clientName />
It fixed my issue, I hope it helps someone.
1
Where on that site does it say to addngModel
. And could you please elaborate why this should be helpful?
– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
add a comment |
For my issue, I was reading github - "ExpressionChangedAfterItHasBeenCheckedError when changing a component 'non model' value in afterViewInit" and decided to add the ngModel
<input type="hidden" ngModel #clientName />
It fixed my issue, I hope it helps someone.
1
Where on that site does it say to addngModel
. And could you please elaborate why this should be helpful?
– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
add a comment |
For my issue, I was reading github - "ExpressionChangedAfterItHasBeenCheckedError when changing a component 'non model' value in afterViewInit" and decided to add the ngModel
<input type="hidden" ngModel #clientName />
It fixed my issue, I hope it helps someone.
For my issue, I was reading github - "ExpressionChangedAfterItHasBeenCheckedError when changing a component 'non model' value in afterViewInit" and decided to add the ngModel
<input type="hidden" ngModel #clientName />
It fixed my issue, I hope it helps someone.
answered Apr 13 '18 at 14:57
DemodaveDemodave
3,46642941
3,46642941
1
Where on that site does it say to addngModel
. And could you please elaborate why this should be helpful?
– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
add a comment |
1
Where on that site does it say to addngModel
. And could you please elaborate why this should be helpful?
– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
1
1
Where on that site does it say to add
ngModel
. And could you please elaborate why this should be helpful?– Peter Wippermann
Jul 18 '18 at 12:35
Where on that site does it say to add
ngModel
. And could you please elaborate why this should be helpful?– Peter Wippermann
Jul 18 '18 at 12:35
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
When I was tracking down this issue, it led me to investigate the link. After reading the article I added the attribute and it fixed my issue. It is helpful if someone runs into the same issue.
– Demodave
Jul 23 '18 at 14:30
add a comment |
Here's my thoughts on what is happening. I have not read the documentation but am sure this is part of why the error is shown.
*ngIf="isProcessing()"
When using *ngIf, it physically changes the DOM by adding or removing the element every time the condition changes. So if the condition changes before it is rendered to the view (which is highly possible in Angular's world), the error is thrown. See explanation here between development and production modes.
[hidden]="isProcessing()"
When using [hidden] it does not physically change the DOM but merely hiding the element from the view, most likely using CSS in the back. The element is still there in the DOM but not visible depending on the condition's value. That is why the error will not occur when using [hidden].
add a comment |
Here's my thoughts on what is happening. I have not read the documentation but am sure this is part of why the error is shown.
*ngIf="isProcessing()"
When using *ngIf, it physically changes the DOM by adding or removing the element every time the condition changes. So if the condition changes before it is rendered to the view (which is highly possible in Angular's world), the error is thrown. See explanation here between development and production modes.
[hidden]="isProcessing()"
When using [hidden] it does not physically change the DOM but merely hiding the element from the view, most likely using CSS in the back. The element is still there in the DOM but not visible depending on the condition's value. That is why the error will not occur when using [hidden].
add a comment |
Here's my thoughts on what is happening. I have not read the documentation but am sure this is part of why the error is shown.
*ngIf="isProcessing()"
When using *ngIf, it physically changes the DOM by adding or removing the element every time the condition changes. So if the condition changes before it is rendered to the view (which is highly possible in Angular's world), the error is thrown. See explanation here between development and production modes.
[hidden]="isProcessing()"
When using [hidden] it does not physically change the DOM but merely hiding the element from the view, most likely using CSS in the back. The element is still there in the DOM but not visible depending on the condition's value. That is why the error will not occur when using [hidden].
Here's my thoughts on what is happening. I have not read the documentation but am sure this is part of why the error is shown.
*ngIf="isProcessing()"
When using *ngIf, it physically changes the DOM by adding or removing the element every time the condition changes. So if the condition changes before it is rendered to the view (which is highly possible in Angular's world), the error is thrown. See explanation here between development and production modes.
[hidden]="isProcessing()"
When using [hidden] it does not physically change the DOM but merely hiding the element from the view, most likely using CSS in the back. The element is still there in the DOM but not visible depending on the condition's value. That is why the error will not occur when using [hidden].
answered May 7 '18 at 3:55
KobusKobus
314
314
add a comment |
add a comment |
My issue was manifest when I added *ngIf
but that wasn't the cause. The error was caused by changing the model in tags then trying to display the changed model in the
*ngIf
statement later on. Here's an example:
<div>changeMyModelValue()</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">myModel.value</div>
To fix the issue, I changed where I called changeMyModelValue() to a place that made more sense.
In my situation I wanted changeMyModelValue() called whenever a child component changed the data. This required I create and emit an event in the child component so the parent could handle it (by calling changeMyModelValue(). see https://angular.io/guide/component-interaction#parent-listens-for-child-event
add a comment |
My issue was manifest when I added *ngIf
but that wasn't the cause. The error was caused by changing the model in tags then trying to display the changed model in the
*ngIf
statement later on. Here's an example:
<div>changeMyModelValue()</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">myModel.value</div>
To fix the issue, I changed where I called changeMyModelValue() to a place that made more sense.
In my situation I wanted changeMyModelValue() called whenever a child component changed the data. This required I create and emit an event in the child component so the parent could handle it (by calling changeMyModelValue(). see https://angular.io/guide/component-interaction#parent-listens-for-child-event
add a comment |
My issue was manifest when I added *ngIf
but that wasn't the cause. The error was caused by changing the model in tags then trying to display the changed model in the
*ngIf
statement later on. Here's an example:
<div>changeMyModelValue()</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">myModel.value</div>
To fix the issue, I changed where I called changeMyModelValue() to a place that made more sense.
In my situation I wanted changeMyModelValue() called whenever a child component changed the data. This required I create and emit an event in the child component so the parent could handle it (by calling changeMyModelValue(). see https://angular.io/guide/component-interaction#parent-listens-for-child-event
My issue was manifest when I added *ngIf
but that wasn't the cause. The error was caused by changing the model in tags then trying to display the changed model in the
*ngIf
statement later on. Here's an example:
<div>changeMyModelValue()</div> <!--don't do this! or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">myModel.value</div>
To fix the issue, I changed where I called changeMyModelValue() to a place that made more sense.
In my situation I wanted changeMyModelValue() called whenever a child component changed the data. This required I create and emit an event in the child component so the parent could handle it (by calling changeMyModelValue(). see https://angular.io/guide/component-interaction#parent-listens-for-child-event
answered Sep 11 '18 at 18:50
goku_da_mastergoku_da_master
2,5882632
2,5882632
add a comment |
add a comment |
@HostBinding
can be a confusing source of this error.
For example, lets say you have the following host binding in a component
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
For simplicity, lets say this property is updated via the following input property:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
this.style_groupBG = carouselConfig.bgColor;
In the parent component you are programatically setting it in ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
this.carousel.carouselConfig = bgColor: 'red' ;
Here's what happens :
- Your parent component is created
- The ImageCarousel component is created, and assigned to
carousel
(via ViewChild) - We can't access
carousel
untilngAfterViewInit()
(it will be null) - We assign the configuration, which sets
style_groupBG = 'red'
- This in turn sets
background: red
on the host ImageCarousel component - This component is 'owned' by your parent component, so when it checks for changes it finds a change on
carousel.style.background
and isn't clever enough to know that this isn't a problem so it throws the exception.
One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding
(such as allowing the parent to control the full bounds of the object).
The better solution, in the parent component is to add detectChanges() after setting the config.
ngAfterViewInit()
this.carousel.carouselConfig = ... ;
this.cdr.detectChanges();
This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.
Consider the case where you don't add @HostBinding
until later during development. Suddenly you get this error and it doesn't seem to make any sense.
add a comment |
@HostBinding
can be a confusing source of this error.
For example, lets say you have the following host binding in a component
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
For simplicity, lets say this property is updated via the following input property:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
this.style_groupBG = carouselConfig.bgColor;
In the parent component you are programatically setting it in ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
this.carousel.carouselConfig = bgColor: 'red' ;
Here's what happens :
- Your parent component is created
- The ImageCarousel component is created, and assigned to
carousel
(via ViewChild) - We can't access
carousel
untilngAfterViewInit()
(it will be null) - We assign the configuration, which sets
style_groupBG = 'red'
- This in turn sets
background: red
on the host ImageCarousel component - This component is 'owned' by your parent component, so when it checks for changes it finds a change on
carousel.style.background
and isn't clever enough to know that this isn't a problem so it throws the exception.
One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding
(such as allowing the parent to control the full bounds of the object).
The better solution, in the parent component is to add detectChanges() after setting the config.
ngAfterViewInit()
this.carousel.carouselConfig = ... ;
this.cdr.detectChanges();
This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.
Consider the case where you don't add @HostBinding
until later during development. Suddenly you get this error and it doesn't seem to make any sense.
add a comment |
@HostBinding
can be a confusing source of this error.
For example, lets say you have the following host binding in a component
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
For simplicity, lets say this property is updated via the following input property:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
this.style_groupBG = carouselConfig.bgColor;
In the parent component you are programatically setting it in ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
this.carousel.carouselConfig = bgColor: 'red' ;
Here's what happens :
- Your parent component is created
- The ImageCarousel component is created, and assigned to
carousel
(via ViewChild) - We can't access
carousel
untilngAfterViewInit()
(it will be null) - We assign the configuration, which sets
style_groupBG = 'red'
- This in turn sets
background: red
on the host ImageCarousel component - This component is 'owned' by your parent component, so when it checks for changes it finds a change on
carousel.style.background
and isn't clever enough to know that this isn't a problem so it throws the exception.
One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding
(such as allowing the parent to control the full bounds of the object).
The better solution, in the parent component is to add detectChanges() after setting the config.
ngAfterViewInit()
this.carousel.carouselConfig = ... ;
this.cdr.detectChanges();
This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.
Consider the case where you don't add @HostBinding
until later during development. Suddenly you get this error and it doesn't seem to make any sense.
@HostBinding
can be a confusing source of this error.
For example, lets say you have the following host binding in a component
// image-carousel.component.ts
@HostBinding('style.background')
style_groupBG: string;
For simplicity, lets say this property is updated via the following input property:
@Input('carouselConfig')
public set carouselConfig(carouselConfig: string)
this.style_groupBG = carouselConfig.bgColor;
In the parent component you are programatically setting it in ngAfterViewInit
@ViewChild(ImageCarousel) carousel: ImageCarousel;
ngAfterViewInit()
this.carousel.carouselConfig = bgColor: 'red' ;
Here's what happens :
- Your parent component is created
- The ImageCarousel component is created, and assigned to
carousel
(via ViewChild) - We can't access
carousel
untilngAfterViewInit()
(it will be null) - We assign the configuration, which sets
style_groupBG = 'red'
- This in turn sets
background: red
on the host ImageCarousel component - This component is 'owned' by your parent component, so when it checks for changes it finds a change on
carousel.style.background
and isn't clever enough to know that this isn't a problem so it throws the exception.
One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding
(such as allowing the parent to control the full bounds of the object).
The better solution, in the parent component is to add detectChanges() after setting the config.
ngAfterViewInit()
this.carousel.carouselConfig = ... ;
this.cdr.detectChanges();
This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.
Consider the case where you don't add @HostBinding
until later during development. Suddenly you get this error and it doesn't seem to make any sense.
answered Aug 2 '18 at 21:01
Simon_WeaverSimon_Weaver
72.6k61449521
72.6k61449521
add a comment |
add a comment |
Debugging tips
This error can be quite confusing, and it's easy to make a wrong assumption about exactly when it's occuring. I find it helpful to add a lot of debugging statements like this throughout the affected components in the appropriate places. This helps understand the flow.
In the parent put statements like this (the exact string 'EXPRESSIONCHANGED' is important), but other than that these are just examples:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / timer callbacks:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
If you run detectChanges
manually add logging for that too:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Then in Chrome debugger just filter by 'EXPRESSIONCHANGES'. This will show you exactly the flow and order of everything that gets set, and also exactly at what point Angular throws the error.
You can also click on the gray links to put breakpoints in.
Another thing to watch out if you have similarly named properties throughout your application (such as style.background
) make sure you're debugging the one you think you - by setting it to an obscure color value.
add a comment |
Debugging tips
This error can be quite confusing, and it's easy to make a wrong assumption about exactly when it's occuring. I find it helpful to add a lot of debugging statements like this throughout the affected components in the appropriate places. This helps understand the flow.
In the parent put statements like this (the exact string 'EXPRESSIONCHANGED' is important), but other than that these are just examples:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / timer callbacks:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
If you run detectChanges
manually add logging for that too:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Then in Chrome debugger just filter by 'EXPRESSIONCHANGES'. This will show you exactly the flow and order of everything that gets set, and also exactly at what point Angular throws the error.
You can also click on the gray links to put breakpoints in.
Another thing to watch out if you have similarly named properties throughout your application (such as style.background
) make sure you're debugging the one you think you - by setting it to an obscure color value.
add a comment |
Debugging tips
This error can be quite confusing, and it's easy to make a wrong assumption about exactly when it's occuring. I find it helpful to add a lot of debugging statements like this throughout the affected components in the appropriate places. This helps understand the flow.
In the parent put statements like this (the exact string 'EXPRESSIONCHANGED' is important), but other than that these are just examples:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / timer callbacks:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
If you run detectChanges
manually add logging for that too:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Then in Chrome debugger just filter by 'EXPRESSIONCHANGES'. This will show you exactly the flow and order of everything that gets set, and also exactly at what point Angular throws the error.
You can also click on the gray links to put breakpoints in.
Another thing to watch out if you have similarly named properties throughout your application (such as style.background
) make sure you're debugging the one you think you - by setting it to an obscure color value.
Debugging tips
This error can be quite confusing, and it's easy to make a wrong assumption about exactly when it's occuring. I find it helpful to add a lot of debugging statements like this throughout the affected components in the appropriate places. This helps understand the flow.
In the parent put statements like this (the exact string 'EXPRESSIONCHANGED' is important), but other than that these are just examples:
console.log('EXPRESSIONCHANGED - HomePageComponent: constructor');
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config', newConfig);
console.log('EXPRESSIONCHANGED - HomePageComponent: setting config ok');
console.log('EXPRESSIONCHANGED - HomePageComponent: running detectchanges');
In the child / services / timer callbacks:
console.log('EXPRESSIONCHANGED - ChildComponent: setting config');
console.log('EXPRESSIONCHANGED - ChildComponent: setting config ok');
If you run detectChanges
manually add logging for that too:
console.log('EXPRESSIONCHANGED - ChildComponent: running detectchanges');
this.cdr.detectChanges();
Then in Chrome debugger just filter by 'EXPRESSIONCHANGES'. This will show you exactly the flow and order of everything that gets set, and also exactly at what point Angular throws the error.
You can also click on the gray links to put breakpoints in.
Another thing to watch out if you have similarly named properties throughout your application (such as style.background
) make sure you're debugging the one you think you - by setting it to an obscure color value.
answered Aug 2 '18 at 21:19
Simon_WeaverSimon_Weaver
72.6k61449521
72.6k61449521
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43375532%2fexpressionchangedafterithasbeencheckederror-explained%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details
– Max Koretskyi aka Wizard
Jul 5 '17 at 9:42