Custom Validation

In this lesson, we will learn about validating our forms and creating custom validation for complex use cases. We will also look at the best way to use reactive forms with validation.

We'll cover the following

Now each of these has its own advantage over one another, and it is totally up to the developer to choose based on their requirements.

One of the many reasons you would choose to work with model-driven forms is to make it easier to unit test and use up other great features of reactive forms, like Custom validation. You can do most of the work from the component class and only put the instances of the input fields on the template.

In this lesson, we will look at how to make the best use of these forms using Custom Validation provided by Angular’s reactive forms.


Users like it when forms are interactive, i.e., they let them know if there is anything wrong that they are doing. To get the best results out of a form, you need to ensure that the users’ inputs are validated, and all the required fields are filled. You can validate that by either using built-in validators or a custom validator.

Validators are either sync type or async. This means the validator either returns an error or null right after the input from the FormControl instance or waits for the returned Promise/Observable to execute to throw a set of validation errors at a later point.

Validation example

this.customerForm= new FormGroup({
    'name': new FormControl(, [Validators.required,

You use Angular’s built-in reactive form validators by adding the Validators to the class and using the validation property. For example

  • Validators.required
  • Validators.minLength(4)

You can see some of the built-in validators here:

required email
maxLength minLength
pattern nullValidator
compose composeAsync

These attributes are the same for both template and class.

Custom validation

Custom validation lets you create your own customized validation based on your requirements.
function classValidator(control: AbstractControl) : {[key : string] : boolean} | null {
return null;

Since our custom validator is a function, we use the function keyword followed by the name of our validator that we want to create. As an argument comes the FormControl or FormGroup for which we use the base class AbstractControl. The next part means the type of value that will be returned by the function. So if there is something wrong with the input field, it returns an object in the form of a key-value pair, where the value is of type boolean, and the key is of type string. If everything works fine with the input field, it returns null.


Let’s create an age validator here.

// Custom Validation code factory validation function

function ageValidator(min: number, max: number){

  return (control: AbstractControl):{[key: string]: boolean} | null => {

  if( control.value !==null && (isNaN(control.value) || control.value <min  || control.value> max)){
    return {'ageValidator': true}
  return null;

To apply this to your input field, use the name of your custom validator on the form control name inside the form group as:

constructor(private fb: FormBuilder){}

    this.customerForm ={
      firstname: ['', [Validators.required, Validators.minLength(5)]],
      email: ['', Validators.required],
      age: [null, ageValidator(20, 70)]

Get hands-on with 1200+ tech skills courses.