In this lesson we will learn about how Angular Reactive Forms Validation works. One of the common tasks that is performed, while building a form is Validation. Here we will learn how to build Reactive Forms and apply Built-in validators. Please read my previous article Reactive Forms in Angular.
How to add a Validator to Reactive Forms
We configure the validators as the second and third argument to the FormControl
, FormGroup
or FormArray
in the component class. The second argument is a collection of sync validators and the third argument is a collection of an async validators.
A Validator is a function that checks the instance of FormControl
, FormGroup
or a FormArray
and returns a list of errors. If the Validator returns a null means that validation has passed
Built-in Validators
The Angular ReactiveForms Module provides several Built-in validators out of the box. They are required, minlength, maxlength & pattern etc.
Reactive Forms Validation Example
Here we created Angular-14 project and we will now add some of the built-in validators. At the end of article you can see the reactive forms validation like below.
Form Model
The below is the contactForm
model that we created to check validation. Here we validate sample form with custom validation.
contactForm = new FormGroup({
firstname: new FormControl('',[Validators.required,Validators.minLength(10)]),
lastname: new FormControl('',[Validators.required, Validators.maxLength(15), Validators.pattern("^[a-zA-Z]+$")]),
email:new FormControl('',[Validators.email,Validators.required]),
gender: new FormControl('',[Validators.required]),
isMarried: new FormControl('',[Validators.required]),
country: new FormControl('',[Validators.required]),
address:new FormGroup({
city: new FormControl('',[Validators.required]),
street: new FormControl('',[Validators.required]),
pincode:new FormControl('',[Validators.required])
})
})
Adding in Built-in Validators
The mentioned earlier, the Angular has provided several built-in validators out of the box.
Required Validator
The required validator is a sync validator, which returns true only if the formcontrol
has a non-empty value entered. The second argument of the FormControl takes the Sync Validator.
firstname: new FormControl('',[Validators.required]),
Minlength Validator
Minlength validator requires the control value must not have less number of characters than the value specified in the validator. For Example, minlength
validator ensures that the firstname
value has at least 10 characters.
firstname: new FormControl('',[Validators.required,Validators.minLength(10)]),
Pattern Validator
This Validator requires that the control value must match the regex pattern provided in the attribute. For example, the pattern ^[a-zA-Z]+$
ensures that the only letters are allowed (even spaces are not allowed). Let us apply this pattern to the lastName
.
lastname: new FormControl('',[Validators.maxLength(15), Validators.pattern("^[a-zA-Z]+$")]),
Email Validator
This Validator requires that the control value must be a valid email address. We apply this to the email field.
email:new FormControl('',[Validators.email,Validators.required]),
Disable Submit button
We have successfully added the validators. Now, we need to disable the submit button if our form is not valid.
The Angular Forms API exposes the state of the forms through the FormGroup
, FormControl
& FormArray
instances. The FormGroup
control has a property valid
, which is set to true
if all of its child controls are valid
.
The contactForm
represents the top-level FormGroup
. We use it to set the disabled
attribute of the submit button.
<button type="submit" [disabled]="!contactForm.valid">Submit</button>
Displaying the Validation/Error messages
We need to provide a short and meaningful error message to the user. We do that by using the error object returned by the FormControl
instance. Every form element has a FormControl
instance associated with it. It exposes the state of form element like valid
, dirty
, touched
etc.
There are two ways in which you can get the reference to the FormControl
. One way is to use the contactForm
variable. We can use contactForm.controls.firstname.valid
to find out if the firstname
is valid.
<div *ngIf="!firstname?.valid && (firstname?.dirty ||firstname?.touched)">
<div [hidden]="!firstname?.errors?.['required']">
First Name is required
</div>
<div [hidden]="!firstname?.errors?.['minlength']">
Min Length is 10
</div>
</div>
Finial Reactive HTML Forms and Typescripts
Reactive Forms HTML
<div class="container">
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()" novalidate>
<div class="row">
<div class="col-md-2">
<label for="firstname">First Name </label>
</div>
<div class="col-md-4">
<input type="text" id="firstname" name="firstname" formControlName="firstname" class="form-control">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!firstname?.valid && (firstname?.dirty ||firstname?.touched)">
<div [hidden]="!firstname?.errors?.['required']">
First Name is required
</div>
<div [hidden]="!firstname?.errors?.['minlength']">
Min Length is 10
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label for="lastname">Last Name </label>
</div>
<div class="col-md-4">
<input type="text" id="lastname" name="lastname" formControlName="lastname" class="form-control">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!lastname?.valid && (lastname?.dirty ||lastname?.touched)">
<div [hidden]="!lastname?.errors?.['pattern']">
Only characters are allowed
</div>
<div [hidden]="!lastname?.errors?.['maxLength']">
Max length allowed is {{lastname?.errors?.['maxlength']?.requiredLength}}
</div>
<div [hidden]="!lastname?.errors?.['required']">
Last Name is required
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label for="email">Email </label>
</div>
<div class="col-md-4">
<input type="text" id="email" name="email" formControlName="email" class="form-control">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!email?.valid && (email?.dirty ||email?.touched)">
<div [hidden]="!email?.errors?.['required']">
email is required
</div>
<div [hidden]="!email?.errors?.['email']">
invalid email id
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label for="gender">Geneder </label>
</div>
<div class="col-md-4">
<input type="radio" value="male" id="gender" name="gender" formControlName="gender"> Male
<input type="radio" value="female" id="gender" name="gender" formControlName="gender"> Female
<input type="radio" value="transgender" id="gender" name="gender" formControlName="gender"> Trans Gender
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!gender?.valid && (gender?.dirty ||gender?.touched)">
<div [hidden]="!gender?.errors?.['required']">
gender is required
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label for="isMarried">Married </label>
</div>
<div class="col-md-4">
<input type="checkbox" id="isMarried" name="isMarried" formControlName="isMarried">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!isMarried?.valid && (isMarried?.dirty ||isMarried?.touched)">
<div [hidden]="!isMarried?.errors?.['required']">
isMarried is required
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label for="country">country </label>
</div>
<div class="col-md-4">
<select id="country" name="country" formControlName="country" class="form-control">
<option [ngValue]="c.id" *ngFor="let c of countryList">
{{c.name}}
</option>
</select>
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!country?.valid && (country?.dirty ||country?.touched)">
<div [hidden]="!country?.errors?.['required']">
country is required
</div>
</div>
</div>
</div>
<div formGroupName="address">
<div class="form-group">
<div class="row space-in-line">
<div class="col-md-2">
<label for="city">City</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="city" formControlName="city">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!city?.valid && (city?.dirty ||city?.touched)">
<div [hidden]="!city?.errors?.['required']">
city is required
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-2">
<label for="street">Street</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="street" formControlName="street">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!street?.valid && (street?.dirty ||street?.touched)">
<div [hidden]="!street?.errors?.['required']">
street is required
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row space-in-line">
<div class="col-md-2">
<label for="pincode">Pin Code</label>
</div>
<div class="col-md-4">
<input type="text" class="form-control" name="pincode" formControlName="pincode">
</div>
<div class="col-md-6 validation-style">
<div *ngIf="!pincode?.valid && (pincode?.dirty ||pincode?.touched)">
<div [hidden]="!pincode?.errors?.['required']">
pincode is required
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
<label> Is Form Valid</label>
</div>
<div class="col-md-4">
{{contactForm.valid}}
</div>
<div class="col-md-6">
</div>
</div>
<div class="row space-in-line">
<div class="col-md-2">
</div>
<div class="col-md-4">
<button type="submit" [disabled]="!contactForm.valid" class="btn btn-primary">Submit</button>
</div>
<div class="col-md-6">
</div>
</div>
</form>
</div>
Reactive Form Typescript File
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.css']
})
export class ReactiveFormsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
contactForm = new FormGroup({
firstname: new FormControl('',[Validators.required,Validators.minLength(10)]),
lastname: new FormControl('',[Validators.required, Validators.maxLength(15), Validators.pattern("^[a-zA-Z]+$")]),
email:new FormControl('',[Validators.email,Validators.required]),
gender: new FormControl('',[Validators.required]),
isMarried: new FormControl('',[Validators.required]),
country: new FormControl('',[Validators.required]),
address:new FormGroup({
city: new FormControl('',[Validators.required]),
street: new FormControl('',[Validators.required]),
pincode:new FormControl('',[Validators.required])
})
})
get firstname() {
return this.contactForm.get('firstname');
}
get lastname() {
return this.contactForm.get('lastname');
}
get email() {
return this.contactForm.get('email');
}
get gender() {
return this.contactForm.get('gender');
}
get isMarried() {
return this.contactForm.get('isMarried');
}
get country() {
return this.contactForm.get('country');
}
get city() {
return this.contactForm.get("address")?.get('city');
}
get street() {
return this.contactForm.get("address")?.get('street');
}
get pincode() {
return this.contactForm.get("address")?.get('pincode');
}
countryList: country[] = [
new country("1", "India"),
new country('2', 'USA'),
new country('3', 'England')
];
onSubmit() {
console.log(this.contactForm.value);
}
}
export class contact {
firstname?:string;
lastname?:string;
gender?:string;
isMarried?:boolean;
country?:string;
address?: {
city:string;
street:string;
pincode:string;
}
}
export class country {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
Output
When we run the application we can see the output like below, where we see how validation is work on the form and how all the form elements are captured in the console window.
Conclusion
In this lesson we will learn about how Angular Reactive Forms Validation works. One of the common tasks that is performed, while building a form is Validation. Here we will learn how to build Reactive Forms and apply Built-in validators.
Leave behind your valuable queries and suggestions in the comment section below. Also, if you think this article helps you, do not forget to share this with your developer community. Happy Coding 🙂
Jayant Tripathy
Coder, Blogger, YouTuberA passionate developer keep focus on learning and working on new technology.