Как управлять Angular2" выражение изменилось после проверки " исключение, когда свойство компонента зависит от текущей даты и времени


мой компонент имеет стили, которые зависят от текущей даты. В моем компоненте у меня есть следующая функция.

  private fontColor( dto : Dto ) : string {

    // date d'exécution du dto
    let dtoDate : Date = new Date( dto.LastExecution );

    (...)

    let color =  "hsl( " + hue + ", 80%, " + (maxLigness - lightnessAmp) + "%)";

    return color;
  }

lightnessAmp вычисляется из текущей даты и времени. Цвет меняется, если dtoDate в последние 24 часа.

точная ошибка заключается в следующем:

Expression has changed after it was checked. Previous value: 
'hsl( 123, 80%, 49%)'. Current value: 'hsl( 123, 80%, 48%)'

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

поэтому я попытался обновить текущую дату и время в каждом жизненном цикле в следующем методе hook, чтобы предотвратить исключение:

  ngAfterViewChecked()
  {
    console.log( "! changement de la date du composant !" );
    this.dateNow = new Date();
  }

...но безуспешно.

5 62

5 ответов:

выполнить обнаружение изменений явно после изменения:

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

constructor(private cdRef:ChangeDetectorRef) {}

ngAfterViewChecked()
{
  console.log( "! changement de la date du composant !" );
  this.dateNow = new Date();
  this.cdRef.detectChanges();
}

Это хороший пост, чтобы понять эту ошибку. Это не слишком долго, чтобы читать.

небольшой workaround для этой проблемы:

ngAfterViewInit() { // or ngOnInit or whatever
    setTimeout(() => {
        this.dateNow = new Date();
    });
}

как упоминалось @leocaseiro на выпуск github.

я нашел 3 решения для тех, кто ищет простых решений.

двигался от ngAfterViewInit до ngAfterContentInit

переезд в ngAfterViewChecked в сочетании с ChangeDetectorRef как предложил на #14748 (комментарий)

держите с ngOnInit () но вызовите ChangeDetectorRef.detectChanges() после внесенные изменения.

Я думаю самое лучшее и самое чистое решение вы можете себе представить это:

@Component( {
  selector: 'app-my-component',
  template: `<p>{{ myData?.anyfield }}</p>`,
  styles: [ '' ]
} )
export class MyComponent implements OnInit {
  private myData;

  constructor( private myService: MyService ) { }

  ngOnInit( ) {
    /* 
      async .. await 
      clears the ExpressionChangedAfterItHasBeenCheckedError exception.
    */
    this.myService.myObservable.subscribe(
      async (data) => { this.myData = await data }
    );
  }
}

испытано с угловым 5.2.9