Naftis
Naftis

Reputation: 4559

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

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:

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?

Upvotes: 4

Views: 6696

Answers (2)

HankCa
HankCa

Reputation: 9629

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).

Upvotes: 1

Thierry Templier
Thierry Templier

Reputation: 202216

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:

Upvotes: 0

Related Questions