Inject Service Into Validator In Angular

Inject Service Into Validator In Angular

In this article, We will learn how to inject a service into an Angular Validator. The validator's validation may be dependent on an external service. It may, for example, need to retrieve data from the back end server in order to validate the value.

Custom Validator

From the last tutorial, here is our greater than custom validator gte. The ValidatorFn function is returned by the gte function.

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'
 
export function gte(val: number): ValidatorFn {
 
  return (control: AbstractControl): ValidationErrors | null => {
 
    let v: number = +control.value;
 
    if (isNaN(v)) {
      return { 'gte': true, 'requiredValue': val }
    }      
 
    if (v <= +val) {
      return { 'gte': true, 'requiredValue': val }
    } 
      
    return null;
  }
}

As illustrated below, we pass the parameter to the validator in the component class.

myForm = new FormGroup({
  numVal: new FormControl('', [gte(10)]),
})

Validator Service

Let's look at how we can inject service into the validator above. To begin, extract the logic from the gte validator and place it in a different service.

Create an entirely new service namely as gte.service.ts

import { Injectable } from '@angular/core';
 
@Injectable({
  providedIn: 'root',
})
export class gteService {
 
  gte(num:any, requiredValue:Number) : Boolean {
 
    if (isNaN(num)) {
      return false;
    }      
  
    if (num <= +requiredValue) {
      return false;
    }
 
    return true;
  }
}

The gteService is really straight forward.

The gte method takes two parameters: val and requiredValue. It determines whether the val is a number bigger than requiredValue. If the answer is yes, the result is true; otherwise, the result is false.

Injecting Service

You can inject service into the validator in two ways. One option is to develop a wrapper service. Another alternative is to directly inject service into the validator.

Wrapper Service

gte.validator.ts should now be open. Make a class called gteValidatorService. Inject the gteService into the constructor. As demonstrated below, copy the validator functiongte into the class and use the gteService.

import { AbstractControl, ValidationErrors, ValidatorFn, Validator, NG_VALIDATORS, FormControl } from '@angular/forms'
import { gteService } from './gte.service';
import { Directive, OnInit, forwardRef, Input, Injectable } from '@angular/core';
 
@Injectable({
  providedIn: 'root',
})
export class gteValidatorService {
 
  constructor(private gteService: gteService) {
  }
 
  gte(val: number): ValidatorFn {
 
    return (control: AbstractControl): ValidationErrors | null => {
  
      let v: number = +control.value;
      if (!this.gteService.gte(v,val)) {
        return { 'gte': true, 'requiredValue': val }
      }
  
      return null;
    }
  }
}

Use the validator as shown below after injecting the gteValidatorService into the component class.

import { Component } from '@angular/core';
import { FormGroup, FormControl, AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'
import { gteValidatorService } from './gte.validator';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
 
  constructor(private gteValidator:gteValidatorService) {
  }
 
 
  myForm = new FormGroup({
    numVal: new FormControl('', [this.gteValidator.gte(10)]),
  })
 
  get numVal() {
    return this.myForm.get('numVal');
  }
 
 
  onSubmit() {
    console.log(this.myForm.value);
  }
}

Inject Service directly into the Validator

Another way is to inject the service directly into the Validator, as illustrated in the example below.

import { AbstractControl, ValidationErrors, ValidatorFn, Validator, NG_VALIDATORS, FormControl } from '@angular/forms'
import { gteService } from './gte.service';
import { Directive, OnInit, forwardRef, Input, Injector } from '@angular/core';
 
export function gte(val: number): ValidatorFn {
 
  return (control: AbstractControl): ValidationErrors | null => {
 
    let injector = Injector.create([ { provide: gteService, useClass:gteService,deps: []}])
    let service = injector.get(gteService);
 
    let v: number = +control.value;
    if (!service.gte(v, val)) {
      return { 'gte': true, 'requiredValue': val }
    }
 
    return null;
 
  }
}

To inject the service instance, we use the Injector.

let injector = Injector.create([ { provide: gteService, useClass:gteService,deps: []}])
let service = injector.get(gteService);

Conclusion

We covered how to inject the service into the validator function in this post. Creating a Validator service is one option. In the Validator service, paste the validator function. Another alternative is to use the inject method to inject the service directly into the validator function.

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

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

Post a Comment

Previous Post Next Post