Expression has changed after it was checked : comment vaincre l'erreur dans Angular

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

« Expression has changed after it was checked » — pourquoi cela se produit et comment vivre avec ?

\n\n

Si vous avez déjà écrit une application en Angular, vous avez sûrement rencontré ce message inquiétant dans la console :

\n\n
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.
\n\n

Cette erreur est un véritable « fléau » pour les développeurs. Des milliers de questions sur Stack Overflow, des centaines d'heures de débogage, des dizaines de crises de nerfs. Mais la bonne nouvelle : on peut non seulement la corriger, mais aussi comprendre pourquoi elle survient. Dans cet article, nous analyserons les principales causes de l'erreur Expression has changed after it was checked, écrirons des exemples en TypeScript et donnerons des solutions concrètes. C'est parti !

\n\n

Que signifie exactement cette erreur ?

\n\n

Angular fonctionne en deux modes : développement (dev mode) et production. En mode développement, le framework effectue une vérification supplémentaire — après chaque cycle de détection des changements, il lance un second passage pour s'assurer que les données n'ont pas changé « à la volée ». Si la valeur change entre le premier et le second passage — Angular plante avec l'erreur ExpressionChangedAfterItHasBeenCheckedError.

\n\n

En termes simples : vous avez dit à Angular « voici les données », il les a vérifiées, puis vous les avez modifiées. Angular se fâche et crie.

\n\n

Top 3 causes de l'erreur

\n\n

1. Modification des données dans les hooks du cycle de vie après ngAfterViewInit

\n\n

La cause la plus fréquente — la tentative de modifier une propriété du composant dans le hook ngAfterViewInit, ngAfterContentInit ou ngAfterViewChecked. À ce moment, Angular a déjà terminé la vérification de la vue, et toute modification provoque l'erreur.

\n\n

Exemple en TypeScript :

\n\n
import { Component, AfterViewInit } from '@angular/core';\n\n@Component({\n  selector: 'app-example',\n  template: '<p>{{ message }}</p>'\n})\nexport class ExampleComponent implements AfterViewInit {\n  message = 'Valeur initiale';\n\n  ngAfterViewInit(): void {\n    // Erreur ! Modification de la propriété après la vérification de la vue\n    this.message = 'Valeur modifiée';\n  }\n}
\n\n

Ici, Angular vérifie d'abord message (valeur « Valeur initiale »), puis appelle ngAfterViewInit, où vous le modifiez en « Valeur modifiée ». Lors de la seconde vérification, Angular constate une divergence et génère l'erreur.

\n\n

2. Opérations asynchrones à l'intérieur du cycle de vie

\n\n

Si vous exécutez du code asynchrone (setTimeout, Promise, Observable) à l'intérieur d'un hook, la mise à jour des données se produit en dehors de la zone de contrôle d'Angular.

\n\n

Exemple :

\n\n
import { Component, OnInit } from '@angular/core';\n\n@Component({\n  selector: 'app-async',\n  template: '<p>{{ data }}</p>'\n})\nexport class AsyncComponent implements OnInit {\n  data = 'Début';\n\n  ngOnInit(): void {\n    setTimeout(() => {\n      this.data = 'Nouvelle valeur';\n    }, 0);\n  }\n}
\n\n

Bien que setTimeout avec un délai de 0 ms s'exécute presque immédiatement, Angular a déjà terminé la vérification. En mode développement, cela entraînera une erreur.

\n\n

3. Composants imbriqués et transmission de données via Input

\n\n

Lorsque le composant parent transmet des données au composant enfant via @Input, et que le composant enfant tente de modifier ces données dans son propre cycle de vie, un conflit survient.

\n\n

Exemple :

\n\n
// Composant parent\n@Component({\n  selector: 'app-parent',\n  template: '<app-child [value]="parentValue"></app-child>'\n})\nexport class ParentComponent {\n  parentValue = 'Original';\n}\n\n// Composant enfant\n@Component({\n  selector: 'app-child',\n  template: '<p>{{ value }}</p>'\n})\nexport class ChildComponent implements AfterViewInit {\n  @Input() value: string = '';\n\n  ngAfterViewInit(): void {\n    this.value = 'Modifié dans le                

Blogs

Book Recommendations