Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 474
Jameel Moideen Avatar asked Aug 02 '17 17:08

Jameel Moideen


People also ask

How do you fix expression has changed after it was checked?

Navigate up the call stack until you find a template expression where the value displayed in the error has changed. Ensure that there are no changes to the bindings in the template after change detection is run. This often means refactoring to use the correct component lifecycle hook for your use case.

How do I use ngAfterViewInit?

ngAfterViewInit() is called after all child components are initialized and checked. In the example above, ngAfterViewInit() gets called one time after ngDoCheck. Triggering the clickMe() function WILL NOT trigger ngAfterViewInit().


2 Answers

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();   } 
like image 157
Richie Fredicson Avatar answered Oct 21 '22 05:10

Richie Fredicson


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:

  • Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error
  • Everything you need to know about change detection in Angular

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.

like image 45
Max Koretskyi Avatar answered Oct 21 '22 06:10

Max Koretskyi