Custom Validation in Template-Driven Angular Forms

jinal shah
5 min readSep 5, 2019

--

Hello Readers,

This article is all about how to implement customized validations when you are working with Template-Driven approach of Angular Forms.

Angular provides built-in validators like required, minlength, maxlength, pattern, etc but when we want any customized logic for the validation and that can be used anywhere in the application too, then we can use Angular Directives to serve the purpose. Inside this directive, we can describe our customized validation function.

First in order to use Template-Driven Forms we have to import the our FormsModule app.module.ts file as below:

Let’s implement two custom validations here, one for Email and other for Confirm Password.

Let’s begin with Email Validation first.

Custom Validation for Email Address:

Now as I said, we will create a directive and name it as EmailValidator.

In our example we want to validate Email address using some regex. So, the Email address that is entered by User should have a valid format according to regex defined.

So, our emailvalidator.directive.ts will look like this:

Okay let’s break down above code and understand their working:

Firstly check the providers array inside @Directive decorator.

The first element of this array is provide: NG_VALIDATORS. This is a special token and this will add (register) our validator to the collection of all existing validators (like required or minlength).This means that all built-in validators are already added in NG_VALIDATORS token and we are adding our own validator to this.

In next element useClass we are providing the class name of our custom directive.

And last element multi: true is a special kind of provider. This will return multiple dependencies as a list of given token. Basically we are adding a new value to the NG_VALIDATORS token by taking advantage of multi providers.

Now, next is our class EmailvalidatorDirective. This class is implementing Validator Interface. So here we need to override the Validate() method of this interface. This validate() method accepts instance of FormControl as its parameter. And this instance is nothing but the control which we want to validate so in our case it will be userEmail control.

And last thing is our emailValidator() method. Inside this method we will actually define our customized logic for validation.This method will return null if Email address is in proper format otherwise return validation error.

Finally we can apply this directive to our template (text input) like below:

<input class=”form-control”
id=”userEmaild”
type=”text”
appEmailvalidator
placeholder=”User Email (required)”
required
ngModel
name=”userEmail”
#userEmailVar=”ngModel”
[ngClass]=”{‘is-invalid’: (userEmailVar.touched || userEmailVar.dirty) && !userEmailVar.valid }” />

Notice above that appEmailvalidator applied as an attribute to the <input> element. This will make a call to validation function when user enters the value to the input box.

For your convenience, below is the full code for both Template (HTML) and TS files:

  1. login.component.html (used bootstrap css)

2)login.component.ts

Okay, so let’s check it out by running our application..!!

Custom Validation for Confirm Password:

Let’s have another validation where we will match the password and confirm password.

For this, we will be adding another directive and name it as passwordvalidator.

This directive will match the value of password and confirm password input fields. If both are matched then it will return null otherwise return validation error.

So, our passwordvalidator.directive.ts will look like this:

As you can see this directive is also having the same structure or format as EmailValidator directive is having. A couple of differences are the method() where we are specifying the logic how both passwords can be matched and another one is in the constructor where we are having a parameter for @Attribute.

Let’s see why we used @Attribute decorator:

The @Attribute decorator returns the value of the specified attribute from the host. We are injecting attribute value via this decorator and assign it to the passwordControl variable. In our case host is the input box of password so the value of passwordControl variable would be the value of password input box.

Okay let’s move on and understand the validate() method.

First, we find the value of password input control in our form and assigned to the Password variable. Then, we read the value of our input (on which this directive is applied) and assign it to ConfirmPassword variable.

const Password = c.root.get(this.PasswordControl);
const ConfirmPassword = c;

After that, we get the latest value of Password whenever there is any change. This can be done by valueChanges(). More precisely we are subscribing to valueChanges to get the real-time value.

if(Password) {
const subscription: Subscription = Password.valueChanges.subscribe(() => {
ConfirmPassword.updateValueAndValidity();
subscription.unsubscribe();
});
}

Inside this Subscribe method we are using updateValueAndValidity() on ConfirmPassword. This method will recalculate the value and validations of ConfirmPassword every time when there is a change in Password.

Then, we are using unsubscribe() on our Password. This will destroy the data that has been previously held by Password when we have applied subscribe() on it.

Now last important thing is to compare Password and ConfirmPassword Values.

return Password && Password.value !== ConfirmPassword.value ? { passwordMatchError: true } : null;

So here we are checking both values are equal or not and returns validation error if they are not equal.

Finally we can apply this directive to our template.

In our HTML now we need to add only one more input box for Confirm Password.

<input class="form-control"
id="CnfrmPasswordId"
type="password"
placeholder="Confirm Password (required)"
required
appPasswordvalidator = "passwordVar"
ngModel
name="CnfmPasswordVar"
#CnfmPasswordVar="ngModel"
[ngClass]="{'is-invalid': (CnfmPasswordVar.touched || CnfmPasswordVar.dirty) && !CnfmPasswordVar.valid }" />

Notice above we have applied appPasswordvalidator as an attribute to the <input> element and we are assigning Password input control to it. By assigning this value we are able to get it in @Attribute variable in the directive’s constructor.

Let’s run the application and check it out..!!

You can find full code for this here:

Thanks for reading. Happy Coding..!!

--

--

jinal shah
jinal shah

Written by jinal shah

Jinal Shah is corporate trainer on different technology like node.Js, Angular,Ionic 2, BOT Framework etc.

Responses (1)