Tutorial

Reactive Forms in Angular: Creating a Custom Validator

Angular

While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Angular and its forms package comes with a Validators class that has some useful validators like required, minLength, maxLength and pattern. Sometimes however, we want to validate fields under more complex or custom rules. This is where a custom validator comes-in very handy.

When using Reactive Forms in Angular, it’s very easy to define custom validators, as they are nothing more than regular functions. You could create the function for your custom validator inside your component file directly if the validator won’t be used elsewhere, but here we’ll assume re-use and create a validator in a separate file.

The Custom Validator Function

For this example, we’ll create a validator that checks if an url entered starts with https and contains .io. Let’s start by creating the file with our validator function, url.validator.ts:

/src/app/validators/url.validator.ts
import { AbstractControl } from '@angular/forms';


export function ValidateUrl(control: AbstractControl) {
  if (!control.value.startsWith('https') || !control.value.includes('.io')) {
    return { validUrl: true };
  }
  return null;
}

Notice how we used the AbstractControl class, which is the base class for form controls as well as form groups and form arrays. This allows us to probe for the value of the control.

If our validation fails, we return an object with a key for the error name and a value of true.

Otherwise, if the validation passes, we simply return null.

Using the Custom Validator

Now it’s as simple as importing our custom validator function and using it the same as any of the built-in validators:

app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ValidateUrl } from './validators/url.validator';

@Component({
  // ...
})
export class AppComponent implements OnInit {
  myForm: FormGroup;
  constructor(private fb: FormBuilder) {}

Notice how, for our websiteUrl form control, we used both the built-in Validators.required as well as our custom ValidateUrl validator.

Accessing the Errors in the Template

You can use the key you defined in the return value of a failing validation to check for the error and display a message in the template:

<div
*ngIf="myForm.get('websiteUrl').errors &&
      myForm.get('websiteUrl').dirty &&
      myForm.get('websiteUrl').errors.validUrl">
  Oops, only urls served over https and only from the .io top-level domain are accepted.
  Talk about restrictions!
</div>
Creative Commons License