web-dev-qa-db-fra.com

ngIf - L'expression a changé après avoir été vérifiée

J'ai un scénario simple, mais je n'arrive pas à le faire fonctionner!

De mon point de vue, j'affiche du texte dans une boîte de hauteur limitée.

Le texte est en cours d'extraction sur le serveur. La vue est mise à jour dès que le texte arrive.

Maintenant, j'ai un bouton 'expand' qui a un ngIf qui devrait afficher le bouton si le texte de la boîte est en train de déborder.

Le problème est que, parce que le texte change quand il est récupéré, l'état du bouton 'développer' devient true après la détection des modifications par Angular ...

Donc j'obtiens cette erreur: L'expression a changé après avoir été vérifiée. Valeur précédente: 'false'. Valeur actuelle: 'true'.

Évidemment le bouton ne montre pas ...

voir ceci Plunker (vérifiez la console pour voir l'erreur ...)

Une idée de comment faire ce travail?

21
naomi

cette erreur se produit parce que vous en dev mode:

Dans dev mode détection de changement ajoute un tour supplémentaire après chaque détection de changement régulière pour vérifier si le modèle a été modifié.

donc, pour forcer la détection de changement exécuter la prochaine tick, nous pourrions faire quelque chose comme ceci:

export class App implements AfterViewChecked {

  show = false; // add one more property

  constructor(private cdRef : ChangeDetectorRef) { // add ChangeDetectorRef
    //...
  }
  //...
  ngAfterViewChecked() {
    let show = this.isShowExpand();
    if (show != this.show) { // check if it change, tell CD update view
      this.show = show;
      this.cdRef.detectChanges();
    }
  }

  isShowExpand()
  {
    //...
  }
}

Démo en direct: https://plnkr.co/edit/UDMNhnGt3Slg8g5yeSNO?p=preview

35
Tiep Phan

Pour une raison quelconque, la réponse de @Tiep Phan ne m'a pas permis de forcer la détection de changement, mais l'utilisation de setTimeout (qui force également la détection de changement) a fonctionné.

De plus, je devais seulement l'ajouter à la ligne incriminée, et cela fonctionnait bien avec le code que j'avais déjà dans ngOnInit au lieu de devoir ajouter ngAfterViewInit.

Exemple:

ngOnInit() {
    setTimeout(() => this.loadingService.loading = true);
    asyncFunctionCall().then(res => {
        this.loadingService.loading = false;
    })
}

Plus de détails ici: https://github.com/angular/angular/issues/6005

5
cs_pupil