Angular reactive forms custom validation: How to create your own

0

A huge part of most applications are forms. Forms to sign-in, forms to gather data, forms for settings and so on. In Angular you can take two different approaches on forms; template-driven forms and reactive forms. This post will focus on custom form validation for reactive forms. Form validation helps to improve the user experience, but also ensures the user can only submit the form in a manner that you intended. The Angular framework gives you most common form validators out of the box. These out of the box options cover a lot of cases but mist of the time you have some special needs tailored to your application. For special validation rules we use Angular reactive forms custom validators. Custom validators are really easy to implement in reactive forms, this is one of the reasons I like reactive forms over template-driven forms

 

Creating a simple Angular reactive form

Before you create a custom validation rule for your Angular form you should first check the out of the box validators Angular gives us. If these do not cover your needs, you can create your custom validator. Lets start with a simple reactive form with a required username and email field (since this is a post on custom form validation I will not explain much more about reactive forms).

<form [formGroup]="userNameForm" (ngSubmit)="formSubmitted()">

  <label>
    First Name:
    <input type="text" formControlName="firstName">
  </label>

  <label>
    Last Name:
    <input type="text" formControlName="lastName">
  </label>

  <button type="submit" [disabled]='!userNameForm.valid'>Submit form</button>

</form>
Angular simple reactive form - HTML

The code above is just a simple reactive form with 2 inputs and a submit button. The submit button is disabled when the form is invalid. In the TypeScript file below we have the FormGroup instance for this form and a formSubmitted method that logs our form instance to the console whenever we click the submit button. We also made the 2 input fields required and added a validator to check for a valid email. If these validation rules do not validate true the submit button is disabled.

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  userNameForm = new FormGroup({
    firstName: new FormControl('', Validators.required),
    lastName: new FormControl('', Validators.required),
  });

  formSubmitted(e) {
    console.log(this.userNameForm);
  }
}
Angular simple reactive form - TypeScript

 

Adding the custom validator

Now that we have a simple form, lets add a custom validation rule. As an example we will only accept emails that include .com. First we create a new file that will contain the custom validator function for your reactive form.

import { AbstractControl } from '@angular/forms';

export function CheckIfEmailEndsWithCom(control: AbstractControl) {
  if (!control.value.includes('.com')) {
    return { dotComCheckFailed: true };
  }
  return null;
}
Custom validtor for Angular reactive form

In this custom validation function you want to access the value of your input field so you can do the custom validation check on it. You can access the value with the AbstractControl class. This is one of the base classes from Angular form controls. This AbstractControl class exposes the value of the input field among many other things. For our example we only are interested in the value property. If you want to dive deeper in the API reference of the AbstractControl class you can check the official docs here.

Once you have the value of the input it’s actually really simple. You write a function that does your custom validation check, if the value passes you return: null. When the value does not pass the validation you return an object with a property name by which to recognize the error and the value true. In our example we do a simple check if ‘.com’ is in the value. If the value contains ‘.com’ we return null, otherwise we return an object with a property named: dotComCheckFailed and a value of true.

Lets add the custom form validator in the FormGroup instance. Just import the custom validator function and add it the array of validators in a FormControl.

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { CheckIfEmailEndsWithCom } from './customValidators/CheckIfEmailEndsWithCom';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  userNameForm = new FormGroup({
    userName: new FormControl('', Validators.required),
    email: new FormControl('', [Validators.email, Validators.required, CheckIfEmailEndsWithCom]),
  });

  formSubmitted(e) {
    console.log(this.userNameForm);
  }
}
Simple Angular reactive form with custom validator - TypeScript

 

Displaying the error from a custom validator

Now that the custom validator is added to the FormControl instance of the email field, this field will stay invalid as long as the custom validator (and the other validators) fail. The last thing we want to do is access the error in the HTML and show an error message when it occurs. This works the same with custom validators as it does with the build in Angular validators. You can use the get function of the FormGroup instance to get the field (or FormControl) you want and access the errors property of this field.

this.userNameForm.get('email').errors
FormGroup get function example

This errors object gets filled whenever the field is dirty and one or more of the validators do not pass. In case of the email field that includes the custom validator. An error message for your custom validation rule in the HTML might look something like this:

  <label>
    Email:
    <input type="text" formControlName="email">
    <span *ngIf="userNameForm.get('email').errors.dotComCheckFailed && userNameForm.get('email').dirty">
      Email must include .com
    </span>
  </label>
Error message for Angular custom form validation

Now whenever the email field is dirty and the error object of it’s FormControl contains a property of dotComCheckFailed, the error message will show.

Hopefully you find this post helpful and a good resource when creating custom form validators for your Angular reactive forms. If you have any questions or improvements, please let me know in the comments and I will get back to you as soon as possible.

Share.

Leave A Reply