Angular FormControl Add and Remove Validators Dynamically

By Arvind Rai, January 16, 2024
On this page we will learn to add and remove sync and async validators dynamically from FormControl in our Angular application. The FormControl provides setValidators and setAsyncValidators to add validators dynamically. The clearValidators and clearAsyncValidators of FormControl remove validators dynamically. When we add or remove a validator at run time, we need to call updateValueAndValidity() of FormControl for the new validation to take effect.

Methods to Add Validators :
Find the methods to add sync and async validators in FormControl dynamically.
addValidators() : Adds sync validators without affecting existing validators.
addAsyncValidators() : Adds async validators without affecting existing validators.
setValidators() : Sets the sync validators overwriting the existing sync validators.
setAsyncValidators() : Sets the async validators overwriting the existing async validators.

Methods to Remove Validators :
Find the methods to remove sync and async validators in FormControl dynamically.
removeValidators() : Removes the specified sync validators without affecting other validators.
removeAsyncValidators() : Removes the specified async validators without affecting other validators.
clearValidators() : Clears all sync validators.
clearAsyncValidators() : Clears all async validators.

After adding or removing validators, we need to call updateValueAndValidity() on that control.

1. setValidators()

The FormControl.setValidators sets the synchronous validators that are active on this control. This method will overwrite any existing sync validators.
Find the method declaration from Angular doc.
setValidators(newValidator: ValidatorFn | ValidatorFn[]): void 
Suppose we have a following FormGroup.
this.userForm = this.formBuilder.group({
  fullName: '',
  username: ['', [ Validators.required ]]   
}); 
Suppose we have following getter methods.
get fullName() {
  return this.userForm.get('fullName');
}  
get username() {
  return this.userForm.get('username');
} 
1. Now we will add validators to fullName control.
this.fullName.setValidators([Validators.required]);
this.fullName.updateValueAndValidity(); 
The setValidators will first clear all existing sync validators and then add the given sync validators. Make sure to call updateValueAndValidity after adding validators to take effect the validation.
2. Now we will add validators to username control. This control has already required validator configured. When we add validators using setValidators, the existing sync validator will be overwritten and only validators configured by setValidators, will be available. Find the code snippet.
this.username.setValidators([Validators.required, Validators.minLength(5), Validators.maxLength(10)]);
this.username.updateValueAndValidity(); 
The username control will have sync validators as required, minLength and maxLength.

2. clearValidators()

The FormControl.clearValidators empties out the sync validator list of this control.
Find the method declaration.
clearValidators(): void 
Find the code snippet.
this.fullName.clearValidators();
this.fullName.updateValueAndValidity(); 
The clearValidators() will clear all sync validators of this control.

3. setAsyncValidators()

The FormControl.setAsyncValidators sets the asynchronous validators that are active on this control. This method will overwrite any existing async validators.
Find the method declaration from Angular doc.
setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[]): void 
Suppose we have a custom async validator existingUsernameValidator(). We will use setAsyncValidators as following.
this.username.setAsyncValidators([existingUsernameValidator(this.userService)]);
this.username.updateValueAndValidity(); 
The username control will be configured with existingUsernameValidator() async validator. The other existing async validators to this control will be overwritten, if any.

4. clearAsyncValidators()

The FormControl.setAsyncValidators empties out the async validator list of this control.
Find the method declaration from Angular doc.
clearAsyncValidators(): void 
Find the code snippet.
this.username.clearAsyncValidators();  
this.username.updateValueAndValidity(); 
The clearAsyncValidators() will clear all async validators of this control.

5. addValidators() and removeValidators()

Here we will learn to use addValidators() and removeValidators() method. We can remove validators only using validator reference added to control.
Find the reference to validator that we will add/remove from control.
fnMinLength = Validators.minLength(2); 
addValidators() :
This validator adds the specified validator or array of specified validators without affecting existing validators.
Find the method declaration from Angular doc.
addValidators(validators: ValidatorFn | ValidatorFn[]): void 
Find the code snippet.
this.fullName?.addValidators([this.fnMinLength]);
this.fullName?.updateValueAndValidity();

console.log(this.fullName?.hasValidator(this.fnMinLength)); 
In the above case, hasValidator() will return true.
removeValidators() :
This method removes a specified validator or array of specified validators without affecting existing validators. removeValidators() removes validators comparing with function reference of validators. We must pass same validator references that have been set or added to control. If the reference does not match, it will be ignored.
Find the method declaration from Angular doc.
removeValidators(validators: ValidatorFn | ValidatorFn[]): void 
Find the code snippet.
this.fullName?.removeValidators([this.fnMinLength]);
this.fullName?.updateValueAndValidity(); 

6. addAsyncValidators() and removeAsyncValidators()

Here we will learn to use addAsyncValidators() and removeAsyncValidators() method. We can remove validators only using validator reference added to control.
Find the reference to an async validator that we will add/remove from control.
existingUnValidator = existingUsernameValidator(this.userService); 
addAsyncValidators() :
This method adds specified async validator or array of async validators without affecting the existing validators.
Find the method declaration from Angular doc.
addAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void 
Find the code snippet.
this.username?.addAsyncValidators([this.existingUnValidator]);
this.username?.updateValueAndValidity();

console.log(this.username?.hasAsyncValidator(this.existingUnValidator)); 
In this case hasAsyncValidator() will return true.
removeAsyncValidators() :
This method removes the specified validator reference or its array without affecting existing validators using function references of validators set or added to this control. If the specified validator reference is not found, it is ignored.
Find the method declaration from Angular doc.
removeAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void 
Find the code snippet.
this.username?.removeAsyncValidators([this.existingUnValidator]);
this.username?.updateValueAndValidity(); 

7. Complete Example with Reactive Form

reactive-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { UserService } from './user-service';
import { existingUsernameValidator } from './existing-username-validator';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-reactive',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule],
  templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {
  userForm!: FormGroup;
  constructor(private formBuilder: FormBuilder, private userService: UserService) {
  }
  ngOnInit() {
    this.userForm = this.formBuilder.group({
      fullName: '',
      username: ['', [Validators.required]],
      password: ['', [Validators.required]]
    });
  }
  get fullName() {
    return this.userForm.get('fullName');
  }
  get username() {
    return this.userForm.get('username');
  }
  get password() {
    return this.userForm.get('password');
  }
  fnMinLength = Validators.minLength(2);
  existingUnValidator = existingUsernameValidator(this.userService);
  addValidators() {
    this.fullName?.addValidators([this.fnMinLength]);
    this.fullName?.updateValueAndValidity();
    console.log(this.fullName?.hasValidator(this.fnMinLength));
  }
  addAsyncValidators() {
    this.username?.addAsyncValidators([this.existingUnValidator]);
    this.username?.updateValueAndValidity();

    console.log(this.username?.hasAsyncValidator(this.existingUnValidator));
  }
  setValidators() {
    this.fullName?.setValidators([Validators.required]);
    this.fullName?.updateValueAndValidity();

    this.username?.setValidators([Validators.required, Validators.minLength(5), Validators.maxLength(10)]);
    this.username?.updateValueAndValidity();

    this.password?.setValidators([Validators.required, Validators.minLength(5), Validators.maxLength(15)]);
    this.password?.updateValueAndValidity();
  }
  setAsyncValidators() {
    this.username?.setAsyncValidators([existingUsernameValidator(this.userService)]);
    this.username?.updateValueAndValidity();
  }
  removeValidators() {
    this.fullName?.removeValidators([this.fnMinLength]);
    this.fullName?.updateValueAndValidity();
  }
  removeAsyncValidators() {
    this.username?.removeAsyncValidators([this.existingUnValidator]);
    this.username?.updateValueAndValidity();
  }
  clearUserValidators() {
    this.fullName?.clearValidators();
    this.fullName?.updateValueAndValidity();

    this.username?.clearValidators();
    this.username?.updateValueAndValidity();

    this.password?.clearValidators();
    this.password?.updateValueAndValidity();
  }
  clearUserAsyncValidators() {
    this.username?.clearAsyncValidators();
    this.username?.updateValueAndValidity();
  }
  onFormSubmit() {
    this.userService.saveUser(this.userForm.value);
    this.userForm.reset();
  }
} 
reactive-form.component.html
<h3>User Form</h3>
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()">
	<table>
		<tr>
			<td>Full Name: </td>
			<td>
				<input formControlName="fullName">
				<div *ngIf="fullName?.dirty && fullName?.errors" class="error">
					<div *ngIf="fullName?.errors?.['required']">
						Full name required.
					</div>
					<div *ngIf="fullName?.errors?.['minlength']">
						Minimum length should be 2.
					</div>
				</div>
			</td>
		</tr>
		<tr>
			<td>Username: </td>
			<td>
				<input formControlName="username">
				<div *ngIf="username?.dirty && username?.errors" class="error">
					<div *ngIf="username?.errors?.['required']">
						Username required.
					</div>
					<div *ngIf="username?.errors?.['minlength']">
						Minimum length should be 5.
					</div>
					<div *ngIf="username?.errors?.['maxlength']">
						Maximum length should be 10.
					</div>
					<div *ngIf="username?.errors?.['usernameExists']">
						Username already exists.
					</div>
				</div>
			</td>
		</tr>
		<tr>
			<td>Password: </td>
			<td>
				<input formControlName="password" type="password">
				<div *ngIf="password?.dirty && password?.errors" class="error">
					<div *ngIf="password?.errors?.['required']">
						Password required.
					</div>
					<div *ngIf="password?.errors?.['minlength']">
						Minimum length should be 5.
					</div>
					<div *ngIf="password?.errors?.['maxlength']">
						Maximum length should be 15.
					</div>
				</div>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<button [disabled]="userForm.invalid">Submit</button><br />
				<button type="button" (click)="addValidators()">Add Sync Validators</button><br />
				<button type="button" (click)="addAsyncValidators()">Add Async Validators</button><br />
				<button type="button" (click)="setValidators()">Set Sync Validators</button><br />
				<button type="button" (click)="setAsyncValidators()">Set Async Validators</button><br />
				<button type="button" (click)="removeValidators()">Remove Validators</button><br />
				<button type="button" (click)="removeAsyncValidators()">Remove Async Validators</button><br />
				<button type="button" (click)="clearUserValidators()">Clear Sync Validators</button><br />
				<button type="button" (click)="clearUserAsyncValidators()">Clear Async Validators</button>
			</td>
		</tr>
	</table>
</form> 
existing-username-validator.ts
import { AsyncValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable } from "rxjs";
import { map } from 'rxjs/operators';
import { UserService } from './user-service';

export function existingUsernameValidator(userService: UserService): AsyncValidatorFn {
  return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
      return userService.unameAlreadyExists(control.value).pipe(
        map(exist => {
           return exist ? {"usernameExists": true} : null;
        }
      ));
 };
} 
user.ts
export class User {
    fullName!: string;
    username!: string;
    password!: string;    
} 
user-service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { User } from './user';

const USERS = ['mahesh', 'krishna'];

@Injectable({
  providedIn: 'root'
})
export class UserService {
  unameAlreadyExists(uname: string): Observable<boolean> {
    if (USERS.indexOf(uname) >= 0)
      return of(true);
    else
      return of(false);
  }
  saveUser(user: User) {
    console.log(user.password);
    console.log(user.username);
    console.log(user.password);
  }
} 
Find the print screen of the output.
Angular FormControl Add and Remove Validators Dynamically

8. References

Angular FormControl
Angular FormBuilder

9. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us