Validating user input for accuracy and completeness helps in improving overall data quality. Angular and its form package turns up with a Validators class that has some beneficial validators like minLength, maxLength, required and pattern. However, occasionally if we wish to validate different fields under more complex/custom rules we can make optimum use of custom validator.
Defining custom validators while using Reactive Forms in Angular comes very easy as they are more of regular functions. One can conveniently generate function for custom validators within the component file in case the validator is not supposed to be used elsewhere. But, herein we will be assuming the re-use and create respective validators in separate files.
Consider the following example:[Step 1: Create a project and add material library
Ng new ng6material Cd ng6mateial Ng add @angular/material Ng serve
Step 2: Create component called reactiveform.component.ts
Ng generate component reactiveform
Configure route of reactiveform.component.ts so that we can navigate it at http://localhost:4200/reactive-form
Step 3: Create a simple form with a model using Angular material and @angular/form
Reactiveform.component.ts
import { Component, OnInit } from '@angular/core'; import{FormBuilder,FormGroup} from '@angular/forms'; @Component({ selector: 'app-login', templateUrl: './reactiveform.component.html', styleUrls: ['./reactiveform.component.css'] }) export class ReactiveformComponent implements OnInit { complexForm : FormGroup; constructor(fb:FormBuilder) { this.complexForm = fb.group({ userName:””, email:””, passWord:””, }) } ngOnInit() {} submitForm(value: any){ console.log(value); } }
Reactiveform.component.html
<div class="login-wrapper"> <mat-card> <div style="text-align:center;"> <img src="https://aimdek-s3-uploads.s3.ap-south-1.amazonaws.com/wp-content/uploads/2016/12/height_70px.png"> </div> <form class="example-form" [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)"> <mat-form-field> <input matInput placeholder="Username" [formControl]="complexForm.controls['userName']" /> </mat-form-field> <br> <mat-form-field> <input matInput placeholder="email" [formControl]="complexForm.controls['email']" /> </mat-form-field> <br> <mat-form-field > <input matInput placeholder="Password" [formControl]="complexForm.controls['passWord']" /> </mat-form-field> <br> <button type="submit" mat-raised-button color="primary" align="right">Login</button> </form> </mat-card> </div>
This will generate the simple model driven reactive form without in build and custom validation.Now we will add in build validation first and then will go through the custom validation.
For validation we need to import Validators from the @angular/forms and have to add that particular Validators in each field of model.
We are going to use Validators.required and Valodators.email in this demo.
Following snippet shows the usage of build in Validators.Reactiveform.component.ts
import { Component, OnInit } from '@angular/core'; import{FormBuilder,FormGroup,Validators,AbstractControl} from '@angular/forms'; @Component({ selector: 'app-login', templateUrl: './reactiveform.component.html', styleUrls: ['./reactiveform.component.css'] }) export class ReactiveformComponent implements OnInit { complexForm : FormGroup; constructor(fb:FormBuilder) { this.complexForm = fb.group({ userName:[null,Validators.required], email:[null,[Validators.required,Validators.email]], passWord:[null,[Validators.required]], }) } ngOnInit() {} submitForm(value: any){ console.log(value); } }
Reactiveform.component.html
<div class="login-wrapper"> <mat-card> <div style="text-align:center;"> <img src="https://aimdek-s3-uploads.s3.ap-south-1.amazonaws.com/wp-content/uploads/2016/12/height_70px.png"> </div> <form class="example-form" [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)"> <mat-form-field [ngClass]="{'has-error':!complexForm.controls['userName'].valid}"> <input matInput placeholder="Username" [formControl]="complexForm.controls['userName']" /> </mat-form-field> <br> <mat-form-field [ngClass]="{'has-error':!complexForm.controls['email'].valid}"> <input matInput placeholder="email" [formControl]="complexForm.controls['email']" /> </mat-form-field> <br> <mat-form-field [ngClass]="{'has-error':!complexForm.controls['passWord'].valid}"> <input matInput placeholder="Password" [formControl]="complexForm.controls['passWord']" /> </mat-form-field> <br> <button type="submit" mat-raised-button color="primary" align="right" [disabled]="!complexForm.valid">Login</button> </form> </mat-card> </div>
In this we are getting observable of Validator in html template and from that we can get boolean value whether the field is valid or not
In above case are getting boolead of valid state from the complexForm object of formGroup which we have created in reactiveform.component.ts and check valid state as following:-
complexForm.valid complexForm.controls['email'].valid
Step 4: Generate custom validator for password
For this we have to create password.validator.ts manually because angular CLI is not providing this in it’s package.
In this file we have to import abstractValidator which is also part of @angular/form package.
Following is the snnipet code of password.validator.ts
import { AbstractControl,Validator } from '@angular/forms'; export function ValidatePassword(control: AbstractControl) { if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{4,20}/.test(control.value)) { return { validPassword: true }; } return null; }
This code will return boolean if password is valid and return NULL if it is not
Now import this validator in reactiveform.component.ts as following.
import { ValidatePassword } from '../validators/password.validator';
Use the ValidatePassword function along with Validator.required in password field of form model as following:
passWord:[null,[Validators.required,ValidatePassword]],
Now we have to use this in reactiveform.component.html inorder to display custom error message for password as following:-
<div class="error" *ngIf="complexForm.get('passWord').errors && complexForm.get('passWord').dirty && complexForm.get('passWord').errors.validPassword"> Password must contain letter and digit. </div>
And there you have it: how to create a custom validator for Angular Reactive Forms. We at AIMDek cater future-proof front-end development services. Get in touch with us at hello@aimdek.com for any queries.