简体   繁体   中英

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Angular

I am trying to make a responsive style of a component. Deal with windows resize. Value will giving by an expression getRight() .

My HTML:

<div [hidden]="index > 3" [style.right]="getRight()" class="chat-box card">
............
</dv>

In my component.ts

import { Component, HostListener } from '@angular/core';

@Component({
 selector: 'app-chat-box',
 templateUrl: './chat-box.component.html',
 styleUrls: ['./chat-box.component.scss']})

export class ChatBoxComponent implements OnInit {

       @HostListener('window:resize', ['$event'])
       onResize(event) {this.currentWidth = event.target.innerWidth;}
       
       currentWidth: number;
       
constructor(){}
ngOnInit() {}

getRight() {
   if(this.currentWidth <= 700 || window.innerWidth <= 700){
          if(this.currentWidth){
             return ((this.currentWidth -320)/2).toString()  + 'px';
           }
       return ((window.innerWidth -320)/2).toString() + 'px';
       }
       if(this.index==1 && window.innerWidth > 700 ){
       return '380px';
   }
return (380 +330).toString() + 'px';}  }

And the error messange will be:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'right: 710px'. Current value: 'right: 11px'.

That's not how you should do it. That function will be called with every change detection cycle. Better is to respond to the resize, and only calculate it then. Way more performant:

<div [hidden]="index > 3" [style.right.px]="right" class="chat-box card"></div>
export class ChatBoxComponent implements OnInit {
  right: number;

  @Input()
  index?: number;

  @HostListener('window:resize')
  setRight() {
    const width = window.innerWidth;
    
    if (width <= 700) {
      this.right = ((width - 320) / 2);
    } else if (this.index === 1 && width > 700) {
      this.right = 380;
    } else {
      this.right = 380 + 330;
    }
  }

  ngOnInit(): void {
    this.setRight();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.index) {
      this.setRight();
    }
  }
}

I'm ignoring some weird logic you've implemented, but I suggest you also take a better look at the angular guides on angular.io

I can however suggest you to use the OnPush change detection strategy. This will already reduce the amount of ExpressionHasChanged errors drastically, makes your app more performant, and increases the logic of when change detection happens.


A more advanced way, would be to use the async pipe in combination with rxjs :

<div [hidden]="(index$ | async) > 3" [style.right.px]="right$ | async" class="chat-box card"></div>
export class ChatBoxComponent {
  @Input()
  set index(index: number) {
    this.index$.next(index || 0);
  }

  readonly index$ = new BehaviorSubject<number>(0);

  readonly right$: Observable<number> = combineLatest([
    this.index$,
    fromEvent(window, 'resize').pipe(
      startWith<Event, void>(void 0)
    )
  ]).pipe(
    map(([index]) => this.getRight(index))
  );

  private getRight(index: number): number {
      const width = window.innerWidth;
    
      if (width <= 700) {
        return (width - 320) / 2;
      }

      if (index === 1 && width > 700) {
        return 380;
      } 
       
      return 380 + 330;
  }
}

working example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM