In Part 1 of Validating Angular Reactive Forms, I covered built-in validators in Angular, which really does cover most use cases. However, just like many scenarios in development, there are exceptions where we’ve got to create our own custom code. That’s where knowing how to create custom validators comes in handy.
Custom Validator Functions
At first glance, custom validation looks kind of intimidating, since custom validators must implement the ValidatorFn
interface below. Let’s break it down.
A validator is a function that takes in a generic control of type AbstractControl
, which is the parent class to the three @angular/forms
building blocks — FormControl
, FormGroup
, and FormArray
. So basically, any kind of control can be validated. This function returns either a ValidationErrors
error map if it’s invalid, and null
if it’s valid.
The ValidationErrors
type defines an error map with a key/value pair. For example, if you wanted to define a custom error called wrongFormat
, you could define an error map like below. We assign it a value of true
to indicate that this wrongFormat
error has been set on the passed in control.
Bringing it all together, let’s create our own custom validator that checks an email control for a “.edu” top-level domain in order to get a student discount. If the user doesn’t enter a “.edu” email, the control will be marked as invalid, and we’ll return an error map with an error called nonEduEmail
.
For reuse throughout our app, we created a separate file called custom-validators.ts
that contains the following CustomValidators
class with our first custom validator called eduEmailValidator
. Back in the component, we’ll import CustomValidators
, then add the new custom validator to the email FormControl
.
Custom Validator Functions with Dependencies
If we want to make our custom validators more generic, we can pass parameters in. This could be helpful if you have data coming in from an API or elsewhere that will define a control’s validation status. To take a step with our existing example, we want a new custom validator that passes in any domain, rather than just a hardcoded “.edu”.
Remember up above when we covered the ValidatorFn
interface, and how it only takes one parameter, an AbstractControl
? Because of this, we’ll have to create a factory function to be able to pass parameters to a validator. This in turn will return an anonymous ValidatorFn
. See the haveDomainValidator
below to view this in action.
In the component, we’ll add the haveDomainValidator
to the anotherEmail
FormControl
. Now we can pass in any top-level domain we’d like to validate on!
Great, we’ve covered two important cases of custom validation — creating basic custom validator functions and custom validators with dependencies. If you want to see the full demo, find it on Stackblitz.
Paired with built-in validators from Part 1, we’re able to validate Angular Reactive Forms for the majority of use cases. And if you want to learn more about Reactive Forms as a whole, check out my full course on Thinkster! We’ll walk through hands-on exercises and learn about cross-field validation as well. Thanks for reading!