ОШИБКА Error: ExpressionChangedAfterItHasBeenCheckedError: Выражение изменилось после того, как оно было проверено. Угловатый

#angular #error-handling

#angular #обработка ошибок

Вопрос:

Я пытаюсь создать адаптивный стиль компонента. Разберитесь с изменением размера Windows. Значение будет выдаваться выражением GetRight().

Мой HTML:

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

В моем компоненте.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 amp;amp; window.innerWidth > 700 ){
       return '380px';
   }
return (380  330).toString()   'px';}  }
  

И сообщение об ошибке будет:

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

Ответ №1:

Это не так, как вы должны это делать. Эта функция будет вызываться с каждым циклом обнаружения изменений. Лучше отреагировать на изменение размера и только потом вычислять его. Намного более производительный:

 <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 amp;amp; width > 700) {
      this.right = 380;
    } else {
      this.right = 380   330;
    }
  }

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

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

Я игнорирую некоторую странную логику, которую вы реализовали, но я предлагаю вам также лучше взглянуть на руководства angular по angular.io

Однако я могу предложить вам использовать OnPush стратегию обнаружения изменений. Это уже значительно уменьшит количество ExpressionHasChanged ошибок, сделает ваше приложение более производительным и повысит логику обнаружения изменений.


Более продвинутым способом было бы использовать async канал в сочетании с 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 amp;amp; width > 700) {
        return 380;
      } 
       
      return 380   330;
  }
}
  

рабочий пример

Комментарии:

1. Спасибо, но это изменение не влияет на правильное значение при изменении размера окна.

2. @ChanchenPork Я обновил свой ответ с помощью stackblitz, в котором реализованы оба вышеуказанных решения, и если вы измените размер iframe справа, вы увидите, что правая часть обновляется, когда эта панель меньше 700

3. Вау, это работа для меня, спасибо. Но если я хочу увеличить this.index на количество открытых окон чата. например, я открываю два компонента чата. Итак, индекс = 2.

4. @ChanchenPork Я ввел индекс @Input() ?

5. Нет, индекс объявлен в классе.