Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 - Expression has changed after it was checked

I am new to angular and trying to combine with easyui angular.

I found this error when trying to open/close dialog:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'klass: l-btn f-inline-row f-content-center l-btn-small l-btn-focus'. Current value: 'klass: l-btn f-inline-row f-content-center l-btn-small'.

And here is my code.

user.component.html

<eui-linkbutton (click)="addAction()" iconCls="icon-add" style="margin-bottom:10px">Add New</eui-linkbutton>
<eui-datagrid 
  [data]="users" style="height1:250px" [filterable]="true" 
  [selectionMode]="'single'"
  [(selection)]="rowSelected"
  [euiContextMenu]="contextMenu"
  >

</eui-datagrid>


<!-- contextmenu -->
<eui-menu #contextMenu (itemClick)="contextClick($event)">
    <eui-menu-item value="edit" text="Edit"></eui-menu-item>
    <eui-menu-item text="Delete"></eui-menu-item>
    <eui-menu-item text="View"></eui-menu-item>
</eui-menu>


<eui-dialog #formDialog [closed]="closed" [draggable]="true" [modal]="true" [title]="isNewRow ? 'Add' : 'Edit'" (close)="closed=true">

  <div class="dialog-button">
    <eui-linkbutton [disabled]="!formObj.valid" (click)="saveAction()" style="width:80px">Save</eui-linkbutton>
    <eui-linkbutton (click)="formDialog.close()" style="width:80px">Cancel</eui-linkbutton>
  </div>
</eui-dialog>

user.component.ts

export class UserComponent implements OnInit {
  rowSelected = null;
  formObj: FormGroup;

  constructor(public userService: UserService, fb: FormBuilder){

    }

  get row(){
      return this.rowSelected;
  }
  set row(value: any){
      this.rowSelected = value;
      this.formObj.reset(this.rowSelected);
  }

  editAction(row){
    this.row = this.rowSelected;
    this.closed = false;
  }

  addAction(){
    console.log('open babe');
    this.row = {
      'id' : null,
      'username' : null,
      'password' : null,
      'email' : null,
      'first_name' : null,
      'last_name' : null
    };

    this.closed = false;
  }


  isNewRow = false;
  editingRow = null;
  closed = true;
  users: Object;

  currentSelection = null;
  ngOnInit() {
    this.userService.getData().subscribe(
      data => this.users = data
    ) 
    console.log('ngoninit');

    this.initRow();
    this.closed = true;
  }

  initRow() {
    this.editingRow = {
      username: null,
      password: null,
      email: null,
      first_name: null,
      last_name: null,
    };
  }

  onAddRow() {
    console.log('open babe');
    this.initRow();
    this.isNewRow = true;
    this.closed = false;
  }

  onEditRow(row) {
    this.isNewRow = false;
    this.editingRow = row;
    this.closed = false;
  }
   contextClick(value){
    if(!this.rowSelected){
      alert('Please select a row first!');
    }
    else{
      if(value == 'edit'){
        this.editAction(this.rowSelected);
      }
    }
  }
}

I have search many tutorial to fix this problem but it seems like the tutorial condition doesn't match with mine.

Do i misunderstand something or missing something practical about angular? what is the proper way to update attribute?

like image 645
24 revs, 19 users 31% Avatar asked Oct 22 '18 04:10

24 revs, 19 users 31%


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 fix ExpressionChangedAfterItHasBeenCheckedError in Angularjs?

A good way to fix the ExpressionChangedAfterItHasBeenCheckedError is to make Angular aware of the fact that you have changed the code after it has completed its first check. You can do this by using setTimeout to make the error go away.

What is ngAfterViewInit?

ngAfterViewInit()linkA callback method that is invoked immediately after Angular has completed initialization of a component's view. It is invoked only once when the view is instantiated.


3 Answers

Use ChangeDetectorRef Service to detect new changes

When a view uses the OnPush (checkOnce) change detection strategy, explicitly marks the view as changed so that it can be checked again.

import { Component, Input, ChangeDetectionStrategy,ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'component',
  templateUrl: 'component.html',
  changeDetection: ChangeDetectionStrategy.OnPush

})


   constructor(cdRef:ChangeDetectorRef){} 
   ngAfterViewInit() {

     this.cdRef.detectChanges();
      }
like image 117
Dinesh Ghule Avatar answered Oct 16 '22 18:10

Dinesh Ghule


I was getting this error after modifying a Map object that was being iterated over using

*ngFor="let entry of myMap.entries()"

The fix that worked for me was just to add ChangeDetectionStrategy.OnPush to my component declaration:

@Component({
  selector: 'component',
  templateUrl: 'component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
like image 29
Paul LeBeau Avatar answered Oct 16 '22 18:10

Paul LeBeau


Can't able to see the open/close dialog code. Here is explanation for the issue. Usually Angular Updates the DOM based on Model object with help of Change Detection. Angular updates the DOM and it got reflected in UI, After that Model also got updated.

Angular don't know what needs to do, so it's reporting an error. We need to manually trigger the change detection in order to reflect the DOM. Try to wrap the section of code inside setTimeout Block

setTimeout(()=>{

});
like image 7
Suresh Kumar Ariya Avatar answered Oct 16 '22 20:10

Suresh Kumar Ariya