Angular FormControl Add and Remove Validators Dynamically

By Arvind Rai, December 15, 2020
This page will walk through Angular FormControl add and remove validators dynamically. 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.

1. Technologies Used

Find the technologies being used in our example.
1. Angular 11.0.3
2. Node.js 12.5.0
3. NPM 6.9.0

2. 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.

3. 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.

4. 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.

5. 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.

6. Complete Example with Reactive Form

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

@Component({
   selector: 'app-reactive-form',
   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');
  }
  addValidators() {
    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();
  }    
  addAsyncValidators() {
    this.username.setAsyncValidators([existingUsernameValidator(this.userService)]);
    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>
			</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)="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);
  }
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
		<app-reactive-form></app-reactive-form>
             `
})
export class AppComponent {
} 
styles.css
table {
    border-collapse: collapse;
}
table, th, td {
    border: 1px solid black;
}
.error {
    color: red;
}
.success {
    color: green;
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './reactive-form.component';

@NgModule({
  imports: [
      BrowserModule,
      ReactiveFormsModule,
  ],
  declarations: [
      AppComponent,
      ReactiveFormComponent
  ],
  providers: [
  ],
  bootstrap: [
      AppComponent
  ]
})
export class AppModule { } 

7. Run Application

To run the application, find the steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
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









©2023 concretepage.com | Privacy Policy | Contact Us