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

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

Closed
altreze opened this Issue Jun 16, 2017 · 198 comments

Comments

Projects
None yet
@altreze

altreze commented Jun 16, 2017

I'm submitting a ...


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

Current behavior

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

Expected behavior

Please tell us about your environment


Angular version: 4.2.2

Browser:
- [X] Chrome (desktop) version Version 58.0.3029.110 (64-bit)
 
For Tooling issues:
- Node version: v6.10.3
- Platform: Mac
@Bigless27

This comment has been minimized.

Bigless27 commented Jun 16, 2017

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

@mpalourdio

This comment has been minimized.

mpalourdio commented Jun 17, 2017

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

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

@jingglang

This comment has been minimized.

jingglang commented Jun 17, 2017

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

from:

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

to:

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

@tytskyi

This comment has been minimized.

tytskyi commented Jun 17, 2017

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

@KevinRattan

This comment has been minimized.

KevinRattan commented Jun 18, 2017

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

@ver-1000000

This comment has been minimized.

ver-1000000 commented Jun 19, 2017

I get same issue when updated 4.1.3 to 4.2.2.

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

constructor(private cdr: ChangeDetectionRef) {
}

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

This comment has been minimized.

MarkPerryBV commented Jun 19, 2017

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

#16592

to resolve this issue: #14321

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

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

@mmenik

This comment has been minimized.

mmenik commented Jun 19, 2017

I get same issue when updated 4.1.3 to 4.2.0 or higher

I attach a little project for reproduce the bug

app-error.zip

@KevinRattan

This comment has been minimized.

KevinRattan commented Jun 19, 2017

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

@altreze

This comment has been minimized.

altreze commented Jun 19, 2017

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

@umens

This comment has been minimized.

umens commented Jun 19, 2017

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

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

@alexzuza

This comment has been minimized.

Contributor

alexzuza commented Jun 19, 2017

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

@umens

This comment has been minimized.

umens commented Jun 19, 2017

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

@tytskyi

This comment has been minimized.

tytskyi commented Jun 19, 2017

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

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

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

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

@umens

This comment has been minimized.

umens commented Jun 19, 2017

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

@tytskyi

This comment has been minimized.

tytskyi commented Jun 19, 2017

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

@umens

This comment has been minimized.

umens commented Jun 19, 2017

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

@saverett

This comment has been minimized.

saverett commented Jun 20, 2017

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

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

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

ComponentA Template:

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

ComponentB Class:

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

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

ComponentA Template:

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

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

@victornoel

This comment has been minimized.

Contributor

victornoel commented Jun 21, 2017

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

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

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

@cobaltutby

This comment has been minimized.

cobaltutby commented Jun 26, 2017

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

@KevinRattan

This comment has been minimized.

KevinRattan commented Jun 26, 2017

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

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

@acidghost

This comment has been minimized.

acidghost commented Jun 26, 2017

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

@mpalourdio

This comment has been minimized.

mpalourdio commented Jun 26, 2017

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

@ghetolay

This comment has been minimized.

Contributor

ghetolay commented Jun 27, 2017

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

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

@aks4it

This comment has been minimized.

aks4it commented Jun 27, 2017

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

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

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

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

@Martin-Wegner

This comment has been minimized.

Martin-Wegner commented Jun 28, 2017

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

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

staticComponent.ts

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

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

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

test.directive.ts

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

dynamic.component.ts

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

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

@Splaktar

This comment has been minimized.

Member

Splaktar commented Feb 8, 2018

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

@alignsoft

This comment has been minimized.

alignsoft commented Feb 8, 2018

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

@Martin-Wegner

This comment has been minimized.

Martin-Wegner commented Feb 8, 2018

@mlc-mlapis wow thanks, it works :)

@ktabarez

This comment has been minimized.

ktabarez commented Feb 22, 2018

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

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

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

Parent Component

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

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

  tickedMessage: string = '';

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

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

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

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

Shared Service

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

@Injectable()
export class AdminService {

  private _tickedMessageAnnounced = new Subject<string>();

  tickedMessageAnnounced$ = this._tickedMessageAnnounced.asObservable();

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

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

Child Component

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

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

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

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

Parent Component(throws exception)

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

  tickedMessage: string = '';

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

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

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

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

Parent Component(with async await)

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

  tickedMessage: string = '';

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

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

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

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

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

@fridoo

This comment has been minimized.

fridoo commented Mar 2, 2018

@ktabarez Thanks, this helped me a lot!

@alignsoft

This comment has been minimized.

alignsoft commented Mar 4, 2018

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

@nhhockeyplayer

This comment has been minimized.

nhhockeyplayer commented Apr 25, 2018

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

@JavierFuentes

This comment has been minimized.

JavierFuentes commented Apr 29, 2018

@ktabarez Thanks a lot!

Your async ... await in subscribe solution works.

@diegofrata

This comment has been minimized.

diegofrata commented May 17, 2018

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

@daddyschmack

This comment has been minimized.

daddyschmack commented May 29, 2018

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

@roelzkie15

This comment has been minimized.

roelzkie15 commented Jun 10, 2018

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

parent.component.html

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

parent.component.ts

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

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

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

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

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

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

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

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

@julianosouzanh

This comment has been minimized.

julianosouzanh commented Jun 21, 2018

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

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

@jordangotbaum

This comment has been minimized.

jordangotbaum commented Jul 18, 2018

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

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

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

Using angular 6.0.0-rc.1

@paxapy

This comment has been minimized.

paxapy commented Jul 20, 2018

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

@DmitryEfimenko

This comment has been minimized.

DmitryEfimenko commented Aug 13, 2018

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

@akankshahardwani26

This comment has been minimized.

akankshahardwani26 commented Aug 21, 2018

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

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

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

@IAMRogerXi

This comment has been minimized.

IAMRogerXi commented Aug 31, 2018

Because you break the rendering pipeline of Angular...

@alokkarma

This comment has been minimized.

alokkarma commented Sep 21, 2018

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

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

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

ComponentA Template:

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

ComponentB Class:

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

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

ComponentA Template:

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

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

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

@dotNetAthlete

This comment has been minimized.

dotNetAthlete commented Sep 25, 2018

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

@mlc-mlapis

This comment has been minimized.

mlc-mlapis commented Sep 25, 2018

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

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

@dotNetAthlete

This comment has been minimized.

dotNetAthlete commented Sep 25, 2018

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

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

@mlc-mlapis

This comment has been minimized.

mlc-mlapis commented Sep 25, 2018

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

@alignsoft

This comment has been minimized.

alignsoft commented Sep 25, 2018

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

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

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

Where the state service has this:

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

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

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

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

@dotNetAthlete

This comment has been minimized.

dotNetAthlete commented Sep 26, 2018

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

@Exlord

This comment has been minimized.

Exlord commented Nov 3, 2018

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

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

This comment has been minimized.

zak905 commented Nov 3, 2018

I found the solution in this issue thread #10762
After I used the AfterContentInit life cycle hook, the error goes away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment