196 votes

Comment gérer Angular2 "L’expression" a changé après avoir été cochée ", exception lorsqu’une propriété de composant dépend de la date et de l’heure actuelles

Mon composant a des styles qui dépendent de courant de type datetime. Dans mon composant, j'ai la fonction suivante.

  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 est calculé à partir du courant de type datetime. Les changements de couleur si dtoDate est dans les dernières 24 heures.

L'erreur exacte est la suivante:

L'Expression a changé après qu'il ait été vérifié. Valeur précédente: 'hsl( 123, 80%, 49%)'. Valeur actuelle: 'hsl( 123, 80%, 48%)'

Je sais que l'exception apparaissent dans le mode de développement qu'au moment où la valeur est vérifiée. Si la valeur est différente de la valeur actualisée, l'exception est levée.

J'ai donc essayé de mettre à jour les datetime à chaque cycle de vie dans la suite de crochet méthode pour empêcher l'exception:

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

...mais sans succès.

419voto

Günter Zöchbauer Points 21340

Exécuter la détection de changement explicitement après le changement:

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

50voto

Sergey Panfilov Points 677

Petite solution de contournement pour ce problème:

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

39voto

tomonari_t Points 421

Ceci est un bon post pour comprendre cette erreur. Ce n'est pas trop long à lire.

29voto

candidJ Points 2751

Comme mentionné par @leocaseiro sur github question.

J'ai trouvé 3 solutions pour ceux qui sont à la recherche de solutions faciles.

Le déplacement d' ngAfterViewInit de ngAfterContentInit

Le déplacement d' ngAfterViewChecked combiné avec ChangeDetectorRefcomme proposé sur #14748 (commentaire)

Garder avec ngOnInit() mais appelez - ChangeDetectorRef.detectChanges()après vos modifications.

2voto

JavierFuentes Points 774

Je pense que la solution la meilleure et la plus propre que vous puissiez imaginer est la suivante:

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

Testé avec Angular 5.2.9

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X