1

And I don't want this. Because I'm validating each element of FormArray asynchronously, I want validators only to run when necessary (i.e. when value of the control they're added to really changes). I also find this behaviour strange because validators don't get executed when value of FormArray changes, only when new element is added.

replication: https://stackblitz.com/edit/angular-reactive-forms-tkdu1n?file=app%2Fapp.component.ts

Any help would be greatly appreciated

2 Answers 2

1
+100

It appears that FormArray executes the validator for every nested FormControl when a new FormControl is pushed inside it, and there's nothing to do about it...

So I forked your stackblitz and I created a stateful validator with a closure, and it did the trick:

form: FormArray;

ngOnInit() {
  this.form = new FormArray([]);
  this.form.push(new FormControl("test", null, this.validatorFactory()));
}

addControl() {
  this.form.push(new FormControl(null, null, this.validatorFactory()));
}

validatorFactory() {
  let previousValue;
  return (c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    if (c.value == previousValue) {
      return Observable.of(null);
    } else {
      previousValue = c.value;
      return Observable.of(null).delay(1000);
    }
  };
}

Forked Stackblitz

Hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

0

Yes, just change the

return Observable.of(null).delay(1000);

to

return Observable.of(null).delay(0);

When you make delay 1000ms you also disable and block the reachability of the statuses of the other instances ( or values), however, when you make delay 0, it does not deal with other instances just checks the current one.

Hope it helps!

3 Comments

I cannot set the delay when using real services instead of mocked ones...
It's still calling validators for each of the controls obviously, just the delay is gone.
Of course, you cant get away from this because you use single validator for them, but in view it does not act like that when you eliminate the delay. If you want to avoid from it you should use new instance of FormArray for each value which of course is terrible idea. Best way I think is doing the validation yourself instead of using FormArray.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.