Dispatching errors in an Angular Reactive Form

Valentin PARSY
Frontend Weekly
Published in
2 min readDec 13, 2017

In my team we recently came accross a problem developping a dynamic reactive form in Angular. In our form we have multiple inputs, coming and going with the flow (it’s beautiful I swear), appearing depending on buttons pressed by the user and all this is orchestrated by a FormBuilder (I will not talk about how to create and manipulate a form here).

The problem we had was that when an input was wrong we wanted some other inputs to be invalidated too. Let’s say you have a really simple FormGroup that we’ll call group (seal of originality) that contains two AbstractControl that represents simple text inputs : input1 and input2. Now the validation of input1 depends on both input1 and input2 values and vice-versa. If you set a Validator on the inputs, validator1 on input1 that will search for input2 value and validator2 on input2 that will search for input1 value and both those validators set our inputs to marked and invalid when needed we face a big issue : nothing happens and your page is stuck … actually what really happens is that when you set a wrong value in input1, validator1 invalidates input2 => which means input2 state has change so validator2 invalidates input1 => which means input1 state has change so validator1 invalidates input2 => which means input2 state has change … you get the picture, you created an infinite loop.

So what we did is set a Validator on group and dispatch the errors to our inputs. This groupValidator takes both input1 and input2 values and when it’s wrong, mark and invalidate both inputs (which will not validate anything, so no loop). Our function looks a little like that :

// errors is an object that contains an error and an information we // use to know where to send the error
dispatchError(form: FormGroup, errors: any){
const paths = getPathsOfTheInputsWeWantToInvalidate(errors.info);
// paths in our case would look like ['form.input1', 'form.inut2']
paths.forEach(path => {
const control = form.get(path);
if(control){
control.markAsTouched();
control.setErrors(errors.error);
}
});
}

I’m still curious weither there is another way of achieving this even if this solution works fine. If you came across a similar problem and found another solution, please share.

--

--

Valentin PARSY
Frontend Weekly

Javascript enthusiast. Developper at @sfeir. Follow me at @ParsyValentin