Angular 4 Custom Validation for Template Driven forms

learned something across the weekend thought of sharing it with you, So this article is about writing your own custom validator for an input field in angular 4. Angular already has many built in validations for form fields which could could be used for basic use-cases.
This article consists an example for a custom email validator using regex. Angular 4 Already has a built-in validator for this “ng-pattern
” . But this article is more focused on creating a base for custom validators so you could improve and use it for other use cases.
So Let’s Begin…
This is how I have defined my Html form group. I have specified my emailvalidator directive and got rid of the ng-pattern attribute.
<div class="form-group" [ngClass]="{
'has-danger': email.invalid && (email.dirty || email.touched),
'has-success': email.valid && (email.dirty || email.touched)}"> <label class="form-control-label" for="email">Email</label> <input type="email" class="form-control" emailvalidator id="email" name="email" [(ngModel)]="lecturer.email" required
#email="ngModel"> <div class="form-control-feedback" *ngIf="email.errors && (email.dirty || email.touched)">
<p *ngIf="email.errors.required">Email is required</p>
<p *ngIf="email.errors.emailvalidator">Please provide a valid email address</p>
</div> </div>
So now we can get started with building our custom validator, before getting started need import few modules from angular forms.
import {
ReactiveFormsModule,
NG_VALIDATORS,
FormsModule,
FormGroup,
FormControl,
ValidatorFn,
Validator
} from '@angular/forms';
Then define the directive , we will be using out EmailValidator class as an existing provide which will be handling the validation part.
import { Directive } from '@angular/core';@Directive({
selector: '[emailvalidator][ngModel]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: EmailValidator,
multi: true
}
]
})
And then the Email Validator class , validator function will be handling the validation. I have used a regex here but you can customize the validation according to the use case. Return message from the emailValidator()
function will decide if the validation has passed or not.
export class EmailValidator implements Validator {validator: ValidatorFn;constructor() {
this.validator = this.emailValidator();
}validate(c: FormControl) {
return this.validator(c);
}emailValidator(): ValidatorFn {
return (c: FormControl) => {
let isValid = /^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/.test(c.value);
if (isValid) {
return null;
} else {
return {
emailvalidator: {
valid: false
}
};
}
}
}
}
and if you decide to write the entire validation block into a single file this is how it would look like.
import {
ReactiveFormsModule,
NG_VALIDATORS,
FormsModule,
FormGroup,
FormControl,
ValidatorFn,
Validator
} from '@angular/forms';
import { Directive } from '@angular/core'; @Directive({
selector: '[emailvalidator][ngModel]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: EmailValidator,
multi: true
}
]
}) export class EmailValidator implements Validator { validator: ValidatorFn; constructor() {
this.validator = this.emailValidator();
} validate(c: FormControl) {
return this.validator(c);
}
emailValidator(): ValidatorFn {
return (c: FormControl) => {
let isValid = /^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/.test(c.value);
if (isValid) {
return null;
} else {
return {
emailvalidator: {
valid: false
}
};
}
}
}
}
and that’s it. Happy Coding :)