Custom validation – Reactive Form (using function) in Angular

In Angular, there are some validation standards in Validators module, but in real applications they won’t be enough so we need to define some other validations to make sure the form is filled exactly as what client need.
Here you can find a sample of custom validator for test the email entered is unique and passwords (2 fields) are match.

Reactive-form.html

<form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
   <input type="text" formControlName="email" [ngClass]="{ 'is-invalid': submitted && f.email.errors }" />
   <div class="invalid-feedback">
      <div>Email is required</div>
      <div>not a valid email address</div>
      <div>Email already exists</div>
   </div> 
   <input type="password" formControlName="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }" />
   <div class="invalid-feedback">
      <div>Password is required</div>
      <div>min 6 characters</div>
   </div> 
   <input type="password" formControlName="confirmPassword" [ngClass]="{ 'is-invalid': submitted && f.confirmPassword.errors }" />
   <div class="invalid-feedback">
      <div>Confirm Password is required</div>
      <div>Passwords must match</div>
   </div> 
   <button>Register</button> 
</form>


Reactive-form.ts

import { Component, OnInit} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MustMatch, uniqueUser } from './custom-valid.validator';

export class ReactiveFormComponent implements OnInit {
  registerForm: FormGroup;
  submitted = false;
  constructor(private formBuilder: FormBuilder) { }
  ngOnInit() {
      this.registerForm = this.formBuilder.group({
          firstName: ['', Validators.required],
          lastName: ['', Validators.required],
          email: ['', [Validators.required, Validators.email]],
          password: ['', [Validators.required, Validators.minLength(6)]],
          confirmPassword: ['', Validators.required]
      }, {
          validator: [MustMatch('password', 'confirmPassword'), uniqueUser('email')]
      });
  }

  get f() { return this.registerForm.controls; }
  onSubmit() {
      this.submitted = true;
      if (this.registerForm.invalid) {
          return;
      }
      console.log(JSON.stringify(this.registerForm.value))
  }
}


custom-valid.validator.ts

import { FormGroup } from '@angular/forms';
import { promise } from 'protractor';
import { resolve } from 'q';

export function MustMatch(controlName: string, matchingControlName: string) {
    return (formGroup: FormGroup) => {
        const control = formGroup.controls[controlName];
        const matchingControl = formGroup.controls[matchingControlName];
        if (matchingControl.errors && !matchingControl.errors.mustMatch) {
            return;
        }

        if (control.value !== matchingControl.value) {
            matchingControl.setErrors({ mustMatch: true });
        } else {
            matchingControl.setErrors(null);
        }
    }
}

export function uniqueUser(controlName: string) {
    const db = ['a@a.a', 'b@a.a'];
    return (formGroup: FormGroup) => {
        const control = formGroup.controls[controlName];
        if (control.errors && !control.errors.uniqueUser) {
           return;
        }
        if (db.indexOf(control.value) != -1) {
            control.setErrors({ uniqueUser: true });
        } else {
            control.setErrors(null);
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s