Chaque EventEmiiter de mon module enfant génère cette erreur et je ne trouve pas de solution pour cela.
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
C'est ce qui déclenche mon EventEmitter:
ngOnChanges(changes: any) {
if (changes.groupingTabValid) {
if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
this.groupingTabValidChange.emit(this.groupingTabValid);
}
}
}
Voici le code HTML de mon composant "principal"
<year-overview-grouping [definitionDetails]="definitionDetails"
[fixedData]="fixedData"
[showValidation]="showValidation"
[groupingTabValid]="groupingTabValid"
(groupingTabValidChange)="setValidators('groupingTab', $event)">
</year-overview-grouping>
Qui appelle cette fonction
public setValidators(validator: string, e: boolean) {
switch (validator) {
case "groupingTab":
this.groupingTabValid = e;
break;
case "selectionTab":
this.selectionTabValid = e;
break;
}
if (this.groupingTabValid && this.selectionTabValid) {
this.valid = true;
} else {
this.valid = false;
}
}
1) Dans une explication simple, quelle est la cause de cette erreur?
2) Quelles mesures puis-je prendre pour résoudre ce problème?
Respecter la règle de flux de données unidirectionnelle
Essayez de reporter l'appel à émettre pour un tick avec un setTimeout
if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
setTimeout(() => this.groupingTabValidChange.emit(this.groupingTabValid), 0)
}
Importez simplement ChangeDetectionStrategy puis ajoutez-le à votre composant
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-bla-bla-bla',
templateUrl: './xxxxx'
})
Vous pouvez éviter d'utiliser setTimeout
et informer Angular que des modifications sont sur le point de se produire après la vérification initiale.
Vous pouvez injecter ChangeDetectorRef
dans votre composant et utiliser sa méthode markForCheck
.
/* ... */
constructor(private cdr: ChangeDetectorRef) {}
/* ... */
if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue {
this.cdr.markForCheck();
this.groupingTabValidChange.emit(this.groupingTabValid);
}
Je commence tout juste à examiner moi-même ce type d'exception, donc aucun expert, mais supposons qu'il soit là pour arrêter les boucles de rétroaction.
Je ne vois pas de raison évidente pour laquelle vous voulez envoyer la valeur à l’enfant et la sauvegarder au parent, mais je suppose que l’enfant applique une logique supplémentaire . service plutôt qu'un composant enfant.
Je réalise que le code de plunker n'a pas de boucle, mais le mécanisme angulaire semble assez simple - il suffit de revérifier les valeurs à la fin du cycle. Notez que groupingTabValid dans le code de votre question envoie directement des commentaires.
En regardant le code de plongeur comme donné, structurellement, le changement d’âge peut être géré sur le parent. L'événement click serait (click)=changeAge(age.value)
et la méthode (sur le parent) pour le gérer
changeAge(inputAge) {
this.newAge = inputAge;
this.person.age = inputAge;
}
Voici une fourchette du plunker. Plunker modifié
Le composant enfant met toujours à jour person.age, mais ne provoque plus d'erreur, car la valeur est identique à celle définie sur le parent.