Cannot Reset Input value based on select box when form is split into child components

I am showing and hiding a FormControl based on another FormControl in the same FormGroup which works using the method below, but when I try to reset the input is hiding, so send its value not sent. I am getting below.

Component method

public hasOtherFundingSource(index: number) {
  const formGroup = this.overviewFunds.at(index);
  const source = formGroup.get('source').value;

  if (source !== 'other') {
    formGroup.get('other_source_desc').reset(); // Throws error
    return false;
  } else {
    return true;
  }
}

      

Mistake

ExampleComponent.html:12 ERROR Error: 
ExpressionChangedAfterItHasBeenCheckedError: 
Expression has changed after it was checked. 
Previous value: 'true'. Current value: 'false'.

      

With some form of @yurzui help, I created a plunker that shows the error. Just change other

to another

in the select box and watch the console log out. It looks like the bug has to do with splitting the FormGroup into subcomponents to reduce size and logic in each class.

If you look at the first plunker that was created, the error does not occur if the form is encapsulated in an application component.

+3


source to share


1 answer


You should avoid any side effect in functions that will be executed every time you view views

<div *ngIf="hasOtherFundingSource(i)">

      

Function

hasOtherFundingSource

will run twice in dev mode on each type of application.

There is a directive NgControlStatus

that checks the validation status.

On first checkout, your form is valid

enter image description here

After that you call formGroup.get('other_source_desc').reset();

and the status becamesinvalid

enter image description here

Then angular works view.checkNoChanges()

and you getExpressionChangedAfterItHasBeenCheckedError

So according to https://angular.io/docs/ts/latest/guide/template-syntax.html#!#no-visible-side-effects



No visible side effects

The template expression must not modify any application state other than the value of the target property.

This rule is important for angular's "unidirectional data flow" policy. You should never worry that reading a component's value might change another displayed value. The view must be stable throughout a single render.

To solve your problem, I did the following:

1) Added event ngModelChange

to select

control

<select formControlName="source" (ngModelChange)="sourceChanged($event, i)">

      

2) Move side effect from hasOtherFundingSource

to SourceChanged function

sourceChanged(value: string, index: number) {
  if (value !== 'other') {
      const formGroup = this.overviewFunds.at(index);
      formGroup.get('other_source_desc').reset();
  }
}

      

Modified Plunker

+3


source







All Articles