ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'

AngularRuntime Error

Angular Problem Overview


I know there are a lot of same questions already posted in stack-overflow and tried different solutions to avoid the run-time error but None of them are working for me.

Error

Component and Html Code

export class TestComponent implements OnInit, AfterContentChecked {
    @Input() DataContext: any;
    @Input() Position: any;
    sampleViewModel: ISampleViewModel = { DataContext: : null, Position: null };
    constructor(private validationService: IValidationService, private modalService: NgbModal, private cdRef: ChangeDetectorRef) {
    }

    ngOnInit() {

    }
    ngAfterContentChecked() {

            debugger;
            this.sampleViewModel.DataContext = this.DataContext;
            this.sampleViewModel.Position = this.Position;
               
    }


<div class="container-fluid sample-wrapper text-center" [ngClass]="sampleViewModel.DataContext?.Style?.CustomCssClass +' samplewidget-'+ sampleViewModel.Position?.Columns + 'x' + sampleViewModel.Position?.Rows">
     //some other html here
</div>

Please Note : This Component is loaded dynamically using DynamicComponentLoader

After My trouble shooting I have identified couple of issues

First of all this child component is loaded dynamically by using DynamicComponentResolver and passing the input values like below

 ngAfterViewInit() {
    this.renderWidgetInsideWidgetContainer();

  }


  renderWidgetInsideWidgetContainer() {
    let component = this.storeFactory.getWidgetComponent(this.dataSource.ComponentName);
    let componentFactory = this._componentFactoryResolver.resolveComponentFactory(component);
    let viewContainerRef = this.widgetHost.viewContainerRef;
    viewContainerRef.clear();
    let componentRef = viewContainerRef.createComponent(componentFactory);
    debugger;
    (<IDataBind>componentRef.instance).WidgetDataContext = this.dataSource.DataContext;
    (<IDataBind>componentRef.instance).WidgetPosition = this.dataSource.Position;
  
  }

Even If I changed my child component html like below I am getting this same error.Just add a angular ngclass attribute

<div class="container-fluid ds-iconwidget-wrapper text-center" [ngClass]="Sample">
  
</div>

My databinding and everything are working fine.Do I need to do anything on parent component? I already tried all the lifecyle events in child component

Angular Solutions


Solution 1 - Angular

you have to tell angular that you updated the content after ngAfterContentChecked you can import ChangeDetectorRef from @angular/core and call detectChanges

import {ChangeDetectorRef } from '@angular/core';

constructor( private cdref: ChangeDetectorRef ) {}
    

ngAfterContentChecked() {

this.sampleViewModel.DataContext = this.DataContext;
this.sampleViewModel.Position = this.Position;
this.cdref.detectChanges();

 }

Solution 2 - Angular

The ngAfterContentChecked lifecycle hook is triggered when bindings updates for the child components/directives have been already been finished. But you're updating the property that is used as a binding input for the ngClass directive. That is the problem. When Angular runs validation stage it detects that there's a pending update to the properties and throws the error.

To understand the error better, read these two articles:

Think about why you need to change the property in the ngAfterViewInit lifecycle hook. Any other lifecycle that is triggered before ngAfterViewInit/Checked will work, for example ngOnInit or ngDoCheck or ngAfterContentChecked.

So to fix it move renderWidgetInsideWidgetContainer to the ngOnInit() lifecycle hook.

Solution 3 - Angular

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

That is a good solution to resolve this problem.

Solution 4 - Angular

I was having trouble with . >ERROR: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'mat-checkbox-checked': 'true'. Current value: 'false'.

The Problem here is that the updated value is not detected until the next change Detection Cycle runs.

The easiest solution is to add a Change Detection Strategy. Add these lines to your code:

import { ChangeDetectionStrategy } from "@angular/core";  // import

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "abc",
  templateUrl: "./abc.html",
  styleUrls: ["./abc.css"],
})

Solution 5 - Angular

If you are using <ng-content> with *ngIf you are bound to fall into this loop.

Only way out I found was to change *ngIf to display:none functionality

Solution 6 - Angular

Two Solutions:

  1. Make Sure if you have some binding variables then move that code to settimeout( { }, 0);
  2. Move your related code to ngAfterViewInit method

Solution 7 - Angular

This code solved my Problem.

import {ChangeDetectorRef } from '@angular/core';

constructor( private cdref: ChangeDetectorRef ) {}

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

Solution 8 - Angular

*NgIf can create a problem here, so either use display none CSS or easier way is to Use [hidden]="!condition"

Solution 9 - Angular

setTimeout(() => { // your code here }, 0);

I wrapped my code in setTimeout and it worked

Solution 10 - Angular

This shall solve the problem

  constructor(private changeDetector: ChangeDetectorRef) {}

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

Solution 11 - Angular

I had the same issue trying to do something the same as you and I fixed it with something similar to Richie Fredicson's answer.

When you run createComponent() it is created with undefined input variables. Then after that when you assign data to those input variables it changes things and causes that error in your child template (in my case it was because I was using the input in an ngIf, which changed once I assigned the input data).

The only way I could find to avoid it in this specific case is to force change detection after you assign the data, however I didn't do it in ngAfterContentChecked().

Your example code is a bit hard to follow but if my solution works for you it would be something like this (in the parent component):

export class ParentComponent implements AfterViewInit {
  // I'm assuming you have a WidgetDirective.
  @ViewChild(WidgetDirective) widgetHost: WidgetDirective;

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private changeDetector: ChangeDetectorRef
  ) {}

  ngAfterViewInit() {
    renderWidgetInsideWidgetContainer();
  }

  renderWidgetInsideWidgetContainer() {
    let component = this.storeFactory.getWidgetComponent(this.dataSource.ComponentName);
    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
    let viewContainerRef = this.widgetHost.viewContainerRef;
    viewContainerRef.clear();
    let componentRef = viewContainerRef.createComponent(componentFactory);
    debugger;
    // This <IDataBind> type you are using here needs to be changed to be the component
    // type you used for the call to resolveComponentFactory() above (if it isn't already).
    // It tells it that this component instance if of that type and then it knows
    // that WidgetDataContext and WidgetPosition are @Inputs for it.
    (<IDataBind>componentRef.instance).WidgetDataContext = this.dataSource.DataContext;
    (<IDataBind>componentRef.instance).WidgetPosition = this.dataSource.Position;
    this.changeDetector.detectChanges();
  }
}

Mine is almost the same as that except I'm using @ViewChildren instead of @ViewChild as I have multiple host elements.

Solution 12 - Angular

RxJS timer()

Like others suggested you can solve the issue by placing your code inside a setTimeout(..) function. It will essentially move the execution outside the event-loop stack, and hence into Angular's next change-detection cycle.

RxJS has its own timeout implementation called timer() - it accepts milliseconds as an argument and returns an observable. Since we only need the execution to happen after the event loop stack is clean (and Angular has finished all its rendering calculations), we can use timer() without any argument (it'll anyway default to 0):

ngAfterViewInit() {
    timer().subscribe(() => {
        // your code here
    })
}

JS event loop schema:

enter image description here

Solution 13 - Angular

Try this, to call your code in ngOnInit()

someMethod() // emitted method call from output
{
    // Your code 
}

ngOnInit(){
  someMethod(); // call here your error will be gone
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJameel MoideenView Question on Stackoverflow
Solution 1 - AngularRichie FredicsonView Answer on Stackoverflow
Solution 2 - AngularMax KoretskyiView Answer on Stackoverflow
Solution 3 - AngularСтанислав ТепляковView Answer on Stackoverflow
Solution 4 - AngularVandana ManhasView Answer on Stackoverflow
Solution 5 - AngularbresleveloperView Answer on Stackoverflow
Solution 6 - AngularChetan LaddhaView Answer on Stackoverflow
Solution 7 - AngularNaresh EtikyalaView Answer on Stackoverflow
Solution 8 - AngularPragati DugarView Answer on Stackoverflow
Solution 9 - AngularAndrisView Answer on Stackoverflow
Solution 10 - AngularAhmed AbdelghanyView Answer on Stackoverflow
Solution 11 - AngularroobyView Answer on Stackoverflow
Solution 12 - AngularShayaView Answer on Stackoverflow
Solution 13 - AngularSurendranath SonawaneView Answer on Stackoverflow