Jak zarządzać wyjątkiem Angular2 "wyrażenie zmieniło się po sprawdzeniu", gdy właściwość komponentu zależy od bieżącej datetime

Mój komponent ma style, które zależą od bieżącej daty. W moim komponencie mam następującą funkcję.

  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 jest obliczana z bieżącej datetime. Kolor zmienia się, jeśli dtoDate jest w ciągu ostatnich 24 godzin.

Dokładny błąd jest następujący:

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

Wiem, że wyjątek pojawia się w trybie deweloperskim tylko w momencie sprawdzania wartości. Jeśli sprawdzona wartość różni się od zaktualizowanej wartości, to wyjątek jest wyrzucany.

Więc próbowałem zaktualizować bieżąca datetime w każdym cyklu życia w następującej metodzie Hooka, aby zapobiec wyjątkowi:

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

...ale bez powodzenia.

Author: Anthony Brenelière, 2016-09-30

5 answers

Uruchom wykrywanie zmian jawnie po zmianie:

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();
}
 192
Author: Günter Zöchbauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 19:20:08

To jest ładny post, aby zrozumieć ten błąd. To nie jest zbyt długo do czytania.

 24
Author: tomonari_t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 08:59:22

Małe obejście tego problemu:

ngAfterViewInit() { // or ngOnInit or whatever
    setTimeout(() => {
        this.dateNow = new Date();
    });
}
 7
Author: Sergei Panfilov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 14:56:56

Jak wspomniano przez @leocaseiro w wydaniu github.

Znalazłem 3 rozwiązania dla tych, którzy szukają łatwych poprawek.

Przejście z ngAfterViewInit do ngAfterContentInit

Przeniesienie do ngAfterViewChecked w połączeniu z ChangeDetectorRef jako zasugerował: #14748 (skomentuj)

Keep with ngOnInit () but call ChangeDetectorRef.detectChanges() after twoje zmiany.

 6
Author: candidJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-07 23:49:22

Myślę, że najlepszym i najczystszym rozwiązaniem można sobie wyobrazić jest to:

@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 }
    );
  }
}

Testowane z Angular 5.2.9

 3
Author: JavierFuentes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-29 19:31:41