Skip to content

Expression changed after it was checked error in Angular 4, but not 2. #428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 of 9 tasks
Bigless27 opened this issue Jun 15, 2017 · 11 comments
Closed
2 of 9 tasks

Comments

@Bigless27
Copy link

Bigless27 commented Jun 15, 2017

This is a...

  • feature request
  • bug report
  • usage question

What toolchain are you using for transpilation/bundling?

  • @angular/cli
  • Webpack
  • Raw ngc
  • SystemJS
  • Rollup
  • Other

Environment

NodeJS Version: 7.0.0
Typescript Version: 2.1.6
Angular Version: 4.2.2
@angular-redux/store version: ^6.0.1
@angular/cli version: (if applicable)
OS:

Link to repo showing the issus

(optional, but helps a lot)
N/A

Actual Behaviour:

When having a value change in a redux's observable subscribe method like visit in the example below

                  @select step$	
                   this.step$
				.takeUntil(this.ngUnsubscribe)
				.subscribe(res => {
					var review = this.ngRedux.getState().review;
					this.visit = res;
			})

I get a expression changed after it was checked error in my html on any element that targets visit. like below.

<button type="button" [ngClass]="{'color-blue': visit === 1 }" >
 </button>

Even if I do the same behavior in another observable. e.q. changing the visit in an observable. I don't get an expression changed after it was checked error.

Expected Behaviour:

Value updates in the component and on the DOM. When I used Angular 2 there were no errors but after upgrading to 4.2.2 I get errors :(.

Stack Trace/Error Message:

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

Additional Notes:

Been at this all day trying to figure out what is causing this and I'm pretty sure that this is taking place in the redux observables subscribe method. Also, using a manual change detection like ref.detectChanges() silences the errors, but, looks like it halts executions of my observable subscribing to the next value until after that round of change detection occurs. Any help would be greatly appreciated!!

@e-schultz
Copy link
Member

Where in your component are you doing the subscribe? Could you provide a more complete code example - as also curious to why you are using select, but then a getState in the subscribe (don't think the use of getState is the issue though).

@Bigless27
Copy link
Author

I don't believe this is a redux issue anymore but an angular 4.2.x issue. angular/angular#17572, there's the current issue on the angular GitHub. When I downgrade to 4.1.x everything works fine. I use getState() because I have two properties on the redux object.

export interface IProgressState {
	step: number;
	review: boolean
}

I want to get both the step and the reviews value.

@select() review$
@select() step$

this.step$
 .takeUntil(this.ngUnsubscribe)
 .subscribe(res => {
  var review = this.ngRedux.getState().review;
  this.visit = res;
}


@e-schultz
Copy link
Member

You could use something like

this.step$
.withLatestFrom(this.review$,(step,review)=>{ 
return { 
  // do something with step and review
}
}).subscribe(res=> { });

with the above - any time step changes, it will get the latest value of review.
Or, if you wanted to do something if either step, or review changes - combineLatest

Learn-rxjs has good examples for combineLatest and withLatestFrom

Also - in the .subscribe - is this being done in the constructor? in the ngOnInit? depending on where you are setting up the subscription - this could impact things for getting that error.

That said - looking through the issue that you linked, there does seem to be a regression that has happened in Angular itself, as other people are reporting similar behaviour, even without redux involved.

If there is anything else I can do to help, let me know - otherwise I will close this issue, but I'll wait for your response first.

@KevinRattan
Copy link

KevinRattan commented Jun 25, 2017

This comment was accidentally posted to the wrong github thread. sorry

@KevinRattan
Copy link

I've been contributing to the thread over at Angular itself - and have reached a point where I think I have isolated the problem arising from the switch from 4.1.3 to 4.2.

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

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

When I run this in 4.1.3 it works - first, the LIST_INGREDIENTS action fires and the new state is returned; then the UPDATE_LOCATION action fires, and the default case is hit, returning the same state.

When I run it in 4.2, the order or actions is reversed. The UPDATE_LOCATION action fires first, returning the old state from default. Then LIST_INGREDIENTS fires, returning the new (changed) state - and the error is raised.

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

@defra91
Copy link

defra91 commented Jul 3, 2017

Same problem here. To fix it I had to roll back from 4.2.2 to 4.1.3

@moarsel
Copy link

moarsel commented Jul 10, 2017

(we're having this problem with ngrx as well)

@marc-wilson
Copy link

Upgraded to 4.3.1 and the issue is still present.

@Bigless27
Copy link
Author

Rolling the version back to 4.1.3 fixed it!

@Bigless27
Copy link
Author

@e-schultz Thank you for that great solution. My observable skills have greatly improved since then. Sorry about getting back to you late but the .subscribe are coming from my ngOnInit(){}

SongZhao pushed a commit to metalshreds/helpinghands that referenced this issue Nov 7, 2017
@saravanakumar-sudo
Copy link

I am also facing the same issues. So then i tried like this. Its working fine for me.
Step 1:
import { Component, OnInit, ChangeDetectorRef, AfterContentChecked } from '@angular/core';
step 2:
export class RegisterComponent implements OnInit, AfterContentChecked {
constructor(private cdRef: ChangeDetectorRef) {}
ngOnInit() {---}

ngAfterContentChecked() {
this.cdRef.detectChanges();
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants