tldr;
Reactive forms in Angular have many benefits, but one that I’ve found especially useful is the fact that I can easily add or remove validation for a given field based on the value of another field. The simplicity of doing that allows us to create complex forms in a simpler manner. Because we can subscribe to the value changes of the form as a whole or a specific field on the form, we can update the validators for any other field automatically. We’ll go over that in this post.
Form Validators
Angular’s reactive forms functionality allows you to add validators to fields on the form in the component’s class file very easily. You can read more about it in this post of mine. I’m not going to completely recap that article here, but let’s set up a demo form for this blog post. Let’s pretend that we need to capture some input from a user about their favorite foods. We’ll just be capturing their favorite dessert in this case. If they have a favorite dessert, we want them to enter it. But if they don’t, we don’t want them to enter anything. Here’s the form:
// form.component.ts
ngOnInit() {
this.foodForm = this._formBuilder.group({
hasFavoriteDessert: [null, Validators.required],
favoriteDessert: ''
})
}
In that code snippet, we created a form with two attributes: hasFavoriteDessert
and favoriteDessert
. The first attribute is required, the second one is not. They need to give a response for hasFavoriteDessert
(possibly through a radio button group or a select element), but currently the favoriteDessert
is not currently required. If we used this form as it is now, the user could submit the form without providing their favorite dessert. But if we required the favoriteDessert
attribute and they didn’t have one, they’d have to provide some value for the form to be valid and that’s not what we want either. That’s where conditionally setting validation comes in to play.
Conditional Validation
AbstractControl
items for Angular forms have a couple of convenient methods that we can use for adding and removing validation based on some condition. Those methods are setValidators
, clearValidators
and updateValueAndValidity
. We’ll use these three together to accomplish our conditional validation. We’ll start by listening for changes on the hasFavoriteDessert
attribute and using the previously mentioned methods to conditionally set the validators. We can do that like this:
// form.component.ts
ngOnInit() {
// form setup
this.foodForm.get('hasFavoriteDessert').valueChanges.pipe(
tap((hasFavoriteDessert: boolean) => {
if (hasFavoriteDessert) {
this.foodForm
.get('favoriteDessert')
.setValidators(Validators.required);
} else {
this.foodForm
.get('favoriteDessert')
.clearValidators();
}
this.foodForm
.get('favoriteDessert')
.updateValueAndValidity();
})
).subscribe()
}
Don’t forget to unsubscribe from this observable when the component is destroyed!
What we’re doing here is subscribing to the observable that emits a value every time the hasFavoriteDessert
attribute value changes. We tap
into the stream and use the current value from the attribute to do something. In this case, we check if it’s true
and if so we set the validators for the control. It can be a single validator like I have done or it can be an array of validators. If the value is false
, we clear all the validators. But the last part is very important as well. Outside the if
statement we call one more method on the control, and that’s the updateValueAndValidity
method. If we don’t call this, we can’t be sure that the component/form will know to require our field or let it be empty.
That’s really all you need to do! Your conditions can be more complex if needed, but the process will be the same either way.
Conclusion
Reactive forms give us a lot of flexibility in our forms and validators are one of my favorite parts of them. From being able to create custom validators (on top of all the built in validators that Angular has) to being able to conditionally add that validation to controls, reactive forms are a great option for your app.
Top comments (0)