Angular2 (beta3) “expression has changed after it was checked” in updating form values

杀马特。学长 韩版系。学妹 提交于 2019-12-10 16:46:05

问题


This is a sort of continuation of my previous post about nested forms in Angular2 (beta 3 with TS) (Angular2 beta: nesting form-based parent/child components and validating from parent), but I'm posting a new question as it refers to a different type of issue.

You can find the repro of the issue described here at http://plnkr.co/edit/iCmmy9at2wF5qY0P6VmV. In short, in this fake scenario I have a component representing a single word from an imaginary dictionary, and another child component used to represent each sense for that word; thus, there is a 1-to-many relation between the parent component and its children. Both have a form-based template, built with a form builder. The child template is inside a NgFor, where I bind each sense from the parent (=word) model. This way, all the properties of each word's sense are automatically bound to the word's model.

Some of these properties have several validators attached (either custom or standard). My issue is that when I programmatically set the word model from the parent component (which also implies setting the value of the form's controls), this seems to trigger some race condition in the validation process, which raises several exceptions of type EXCEPTION: Expression '!definitionCtl.valid' has changed after it was checked. Previous value: 'true'. Current value: 'false', which block further code execution.

AFAIK, the only information which seems related to this issue is here:

  • https://github.com/angular/angular/issues/5992,
  • Angular2: Nested *ngFor resulting in 'Expression has changed after it was checked'

Yet a solution for my issue does not seem to be at hand from those discussions, unless (if I understand well) I opt for manually managing all my bindings, which I'd like to avoid, as in the real-world application there will be lots of them. Could anyone help?


回答1:


You could try to disable the Angular2 dev mode:

import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
import {enableProdMode} from 'angular2/core';

enableProdMode();

bootstrap(App, [])
  .catch(err => console.error(err));

See the Günter's answer for more details:

  • In Angular2, why are there 2 times check for content and view after setTimeout?



回答2:


I had this problem. There was lots of discussion about this in https://github.com/angular/angular/issues/6005. We had a different situation and solution (i've just listed it on that page).

  • Our Angular app - https://github.com/GeoscienceAustralia/GNSS-Site-Manager, has model reactive forms that are nested and built across multiple components in ngOnInit(). Some of these forms are collapsed with an ngIf in the template
  • The data is read-in also in a ngOnInit() and was being applied with a theModelForm.patchValue(data)
  • This error was surfacing when one of the collapsed forms was expanded. It is related to the fact that the DOM wasn't built because the form was created in the ngOnInit() that didn't fire until it was expanded. Take out the patchValue() and the problem went away
  • We came up with two solutions
    1. Before the patchValue() run a this._changeDetectionRef.detectChanges();. And change the ngIf to a [hidden] so that the form and DOM is fully built. The down-side of this is the time and memory cost as the complete form and the related DOM is created (this may not be a problem in many apps but it was for us as we have a gigantic form).
    2. The better solution is to apply the patchValue() (or setValue() if the data and fields are 1:1) in the components and thus only happens when the form is created in ngOnInit().

I haven't committed these changes yet (22/3/17).



来源:https://stackoverflow.com/questions/35219844/angular2-beta3-expression-has-changed-after-it-was-checked-in-updating-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!