Angular is a popular front-end framework for building dynamic and interactive web applications. One of its key features is the ability to easily manage forms, including form validation. In this series of posts, we will explore various examples of Reactive Forms Validation in Angular, from the simplest to more advanced ones.
In this first part of the series, we will focus on single control validation. This means that we will be applying validation to individual form controls, rather than the entire form. We will discuss how to add both synchronous and asynchronous validators to a single control, as well as the execution order of these validators. So let’s dive in and see how Angular makes form validation a breeze.
Let’s Start From the Simplest Possible Example
To get started, let’s create a simple Angular component with a single form control. We will use the FormControl class provided by Angular to represent our form control. Here’s the code for our component:
export class SingleControlComponent {
readonly emailControl = new FormControl();
}
And here’s the corresponding markup in our Angular template:
<label for="email">Email</label>
<input name="email" type="text" [formControl]="emailControl">
If we run this example, we will see a basic input field for entering an email address. However, at this point, there is no validation applied to this control. Let’s change that by adding some validators.
Adding Synchronous Validation to the FormControl
Angular provides a set of built-in validators that we can use to validate our form controls. These validators are available in the Validators class, which we can import into our component. Let’s take a look at two commonly used validators: required and email.
Validators.required
As the name suggests, this validator checks whether the form control has a non-empty value. If the control is empty, it will be considered invalid. We can add this validator to our emailControl by passing it as the second argument in the FormControl constructor:
readonly emailControl = new FormControl(null, [Validators.required]);
Now, if we try to submit the form without entering an email address, we will see an error message indicating that the field is required.
Validators.email
This validator checks whether the value of the form control matches the pattern of a valid email address. It is based on the definition of a valid email address in the WHATWG HTML specification, with some enhancements to incorporate more RFC rules. We can add this validator to our emailControl as well:
readonly emailControl = new FormControl(null, [Validators.required, Validators.email]);
Now, if we enter an invalid email address, such as “abc123”, we will see an error message indicating that the email is not valid.
Implementing Asynchronous Validator
In addition to synchronous validators, Angular also allows us to add asynchronous validators to our form controls. These validators are functions that return a Promise or an Observable, and they are executed asynchronously. This means that we can perform more complex validation logic, such as making an HTTP request to check if a username is available, before allowing the form to be submitted.
Let’s take a look at how we can implement an asynchronous validator for our emailControl. First, we need to create a function that returns a Promise or an Observable. This function will receive the form control as its parameter and should return either null if the control is valid, or an object with an error message if the control is invalid. For example, we can create a simple function that checks if the email address already exists in our database:
function checkEmailExists(control: FormControl): Promise<any> | Observable<any> {
return new Promise((resolve, reject) => {
// Make an HTTP request to check if the email exists
// If it does, resolve with an error message
// Otherwise, resolve with null
});
}
Next, we can add this function as an asynchronous validator to our emailControl:
readonly emailControl = new FormControl(null, [Validators.required, Validators.email], [checkEmailExists]);
Now, whenever the user enters an email address, this function will be executed asynchronously to check if the email already exists. If it does, the form control will be considered invalid and an error message will be displayed.
Validators Execution Order
When we have multiple validators applied to a single form control, it’s important to understand the order in which these validators are executed. By default, Angular executes validators in the order they are passed into the FormControl constructor. This means that if we have both synchronous and asynchronous validators, the synchronous validators will be executed first, followed by the asynchronous ones.
However, we can also specify a custom execution order for our validators by using the updateValueAndValidity() method on the form control. This method allows us to pass in an object that specifies the execution order of our validators. For example, we can specify that the asynchronous validator should be executed before the synchronous ones:
this.emailControl.updateValueAndValidity({ emitEvent: false, onlySelf: true, asyncValidatorsFirst: true });
This can be useful when we want to prioritize certain validators over others, or when we want to avoid unnecessary validation checks.
Conclusion
In this first part of our series on Angular Forms Validation, we have explored how to add both synchronous and asynchronous validators to a single form control. We have also seen how we can specify a custom execution order for our validators. In the next part, we will dive deeper into form validation by looking at how we can validate multiple form controls together.