Async Validator In Angular

Async Validator In Angular

In this article, We will learn how to make a custom async validator in Angular. The process of generating an async validator is quite similar to the process of building Sync validators. The main distinction is that async Validators must produce an observable as a consequence of the validation (or as a Promise).

As with sync validators, Angular does not have any built-in async validators. However, it is very simple to construct one.

How to Create Async Validator

Creating an async validator is as simple as writing a function that follows the rules below.

The AsyncValidatorFn Interface, which defines the signature of the validator function, must be implemented by the function.

Either an observable or a promise must be returned by the function.

If the input is valid, return null; otherwise, return ValidationErrors.

AsyncValidatorFn

The AsyncValidatorFn is an interface that defines the validator function's signature.

interface AsyncValidatorFn {
  (control: AbstractControl): Promise<validationerrors null=""> | Observable<validationerrors null="">
}

The AbstractControl is sent to the function. FormControl, FormGroup, and FormArray are all derived from this basic class. If the validation succeeds, the validator function must return a list of errors, i.e. ValidationErrors, or null if the validation fails. The return type is the only difference between it and the Sync Validator. Either a promise or an observable must be returned.

Async Validator Example

In the Angular tutorial on how to develop a custom validator, we built the gte validator. Let's transform that validator to an Async Validator in this Async Validator Example.

Create an Angular application from scratch. Copy the following code into the gte.validator.ts file.
import { AbstractControl, ValidationErrors } from '@angular/forms'
 
import { Observable, of } from 'rxjs';
 
export function gte(control: AbstractControl): 
         Observable<validationerrors> | null {
 
    const v:number=+control.value;
 
    console.log(v)
    
    if (isNaN(v)) {
      return of({ 'gte': true, 'requiredValue': 10 })
    }      
 
    if (v <= 10) {
      return of({ 'gte': true, 'requiredValue': 10 })
    } 
 
    return of(null)
 
}

Import the AbstractControl and ValidationErrors from @angular/forms first. We also need to import Observable from the rxjs package because we need to return an observable.

The AsyncValidatorFn Interface must be followed by the validator function. The AbstractControl should be passed to it as a parameter. It can take the form of a FormControl, FormGroup, or FormArray.

If any errors are identified, the function must return ValidationErrors; otherwise, it must return null. They must be returned as observable.

ValidationErrors is a [key: string]: any key-value pair object that defines the broken rule. The string is the key, and it should include the name of the breached rule. The value can be anything, though it's most commonly true.

The validation logic is straightforward. Use the isNaN method to see if the control's value is a number. Check to see if the number is less than or equal to ten. If both rules are followed,

If the validation fails, the ValidationErrors are returned. You can use anything for the key, although it is recommended that you use the validator's name, i.e. gte. Also, set the value to true. You can also specify a string value.

As illustrated in the example above, you can return several key-value pairs. The value 10 is returned by the second key requiredValue. This is what we use in the template to display the error message.

We convert the result into an observable and return it using the operator.

Using the Async Validator

Before you can use this validator, you must first import it into the component class.
import { gte } from './gte.validator';

As seen below, add the validator to FormControl's Async Validator collection. The async validator is FormControl's third argument.
myForm = new FormGroup({
  numVal: new FormControl('', [gte]),
})

That is all there is to it. The whole code for app.component.ts is shown below.
import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms'
import { gte } from './gte.validator';
 
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
 
  constructor() {
  }
 
 
  myForm = new FormGroup({
    numVal: new FormControl('',null, [gte]),
  })
 
  get numVal() {
    return this.myForm.get('numVal');
  }
 
 
  onSubmit() {
    console.log(this.myForm.value);
  }

The following code is the complete code of the app.component.html file
<h1>Async Validator in Angular</h1>
 
<h2>Reactive Form</h2>
 
<form autocomplete="off" formgroup="" myform="" ngsubmit="" novalidate="" onsubmit="">
 
  <div>
    <label>Number :</label>
    <input formcontrolname="numVal" id="numVal" name="numVal" type="text" />
    <div ngif="!numVal.valid && (numVal.dirty ||numVal.touched)">
      <div ngif="numVal.errors.gte">
        The number should be greater than {{numVal.errors.requiredValue}}
      </div>
    </div>
 
  </div>
 
 
  <p>Is Form Valid : {{myForm.valid}} </p>
 
  <p>
    <button disabled="" myform.valid="" type="submit">Submit</button>
  </p>
 
 
</form>

The following code is the complete code of the app.module.ts file
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
 
 
import { AppComponent } from './app.component';
 
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The use case for Async Validators

When we need to send an HTTP request to the server to check if the data is legitimate, we use the async validator.

The code below demonstrates how to send an HTTP Request to verify data.

If the data is valid, we will return nothing; otherwise, we will return ValidationErrors ('InValid': true).
import { AbstractControl, ValidationErrors } from '@angular/forms'
import { Observable, pipe } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
 
export function validate(control: AbstractControl): Observable<validationerrors> | null {
 
  const value: string = control.value;
 
  return this.http.get(this.baseURL + 'checkIfValid/?value=' + value)
    .pipe(
      debounceTime(500),
      map( (data:any) =>  {
          if (!data.isValid) return ({ 'InValid': true })
      })
    )
  
}

You may also inject service into the validator and pass parameters to it.

You can also use combineLatest to check the input and blend data from several observables.

Conclusion

In this article, We covered how to make a custom async validator in Angular.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in the comment section.

Post a Comment

Previous Post Next Post