dans ParentComponent =>
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ''. Current value: '[object Object]'.
at viewDebugError (vendor.bundle.js:8962)
at expressionChangedAfterItHasBeenCheckedError (vendor.bundle.js:8940)
Composant parent Html
<div>
<app-child-widget [allItems]="allItems" (notify)="eventCalled($event)"></app-child-widget>
<div>
Composant parent
export class ParentComponent implements OnInit {
returnedItems: Array<any> = [];
allItems: Array<any> = [];
constructor(
) { }
ngOnInit() {
this.allItems = // load from server...
}
eventCalled(items: Array<any>): void {
this.returnedItems = items;
}
}
Composante enfant
@Component({
selector: 'app-child-widget',
templateUrl: 'child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter();
@Input() private allItems: Array<any>;
constructor() { }
ngOnInit() {
doSomething();
}
doSomething() {
this.notify.emit(allItems);
}
}
L'article Tout ce que vous devez savoir sur l'erreur ExpressionChangedAfterItHasBeenCheckedError
explique ce comportement en détail
Votre problème est très similaire à celui-ci mais au lieu de mettre à jour la propriété parent via un service, vous le mettez à jour via la diffusion d'événements synchrones. Voici la citation du réponse liée :
Au cours du cycle de résumé, Angular effectue certaines opérations sur les directives enfant. L'une de ces opérations consiste à mettre à jour les entrées et à appeler le hook de cycle de vie ngOnInit sur les directives/composants enfants. L'important est que ces opérations soient effectuées dans un ordre strict:
- Mettre à jour les entrées
- Appeler ngOnInit
Ainsi, dans votre cas, Angular a mis à jour la liaison d'entrée allItems
sur le composant enfant, puis a appelé onInit
sur le composant enfant, ce qui a entraîné une mise à jour du composant allItems
du composant parent. Vous avez maintenant une incohérence dans les données. Le composant parent a une valeur alors que l'enfant en est une autre. Si Angular continue à synchroniser les modifications, vous obtiendrez une boucle infinie. C'est pourquoi, au cours du prochain cycle de détection de changement, Angular a détecté que allItems
avait été modifié et a généré une erreur.
Il semble que ce soit un défaut de conception d’application lorsque vous mettez à jour details
à partir des composants parent et enfant. Si ce n'est pas le cas, vous pouvez résoudre le problème en émettant l'événement de manière asynchrone de la manière suivante:
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter(true);
^^^^^^-------------
Mais il faut faire très attention. Si vous utilisez un autre crochet comme ngAfterViewChecked
qui est appelé à chaque cycle de résumé, , vous vous retrouverez dans une dépendance cyclique!
Dans mon cas, je changeais l'état de mes données - cette réponse vous obligeait à lire l'explication du cycle de digestion par AngularInDepth.com - dans le niveau html, tout ce que j'avais à faire était de changer la façon dont je traitais les données, :
<div>{{event.subjects.pop()}}</div>
dans
<div>{{event.subjects[0]}}</div>
Résumé: au lieu de popping - qui retourne et supprime le dernier élément d'un tableau, changeant ainsi l'état de mes données - j'ai utilisé la méthode habituelle pour obtenir mon données sans changer d'état, empêchant ainsi l'exception .