Search code examples
angularangular-reactive-forms

Angular reactive form hasValidator return false for custom validator function


import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

export function trimValidator(minlength: number, maxlength: number): ValidatorFn {
  return ({ value }: AbstractControl): ValidationErrors | null => {
    const trimValue = value?.trim() || '';
    if (trimValue.length < minlength) {
      return { minlength: true }; 
    } else if (trimValue.length > maxlength) {
      return { minlength: true }; }
    };
}

// ====================================================================

myform = this.fbgroup({
  name: ['', [Validators.required]],
  description: ['', [trimValidator(10, 3000)]]
});

// When i access default validator through hasValidator then i got true but when i pass custom validator functiion to hasvalidator then return me false

// inside custom-directive.ts

this.myform.get('name')?.hasValidator(Validator.required)  // true

this.myform.get('description')?.hasValidator(trimValidator(10, 3000))  // false

Solution

  • From the hasValidator docs:

    The provided validator must be a reference to the exact same function that was provided.

    Create a variable used to store the reference:

    trimValidator = trimValidator(10, 3000);
    
    myform = this.fb.group({
       name: ['', [Validators.required]],
      description: ['', [this.trimValidator]],
    });
    

    Provide the variable to hasValidator:

    this.myform.get('description')?.hasValidator(this.trimValidator)
    

    Note that your current trimValidator has an error that returns undefined and it is not matched with the return type. You should add return null:

    export function trimValidator(
      minlength: number,
      maxlength: number
    ): ValidatorFn {
      return ({ value }: AbstractControl): ValidationErrors | null => {
        const trimValue = value?.trim() || '';
        if (trimValue.length < minlength) {
          return { minlength: true };
        } else if (trimValue.length > maxlength) {
          return { minlength: true };
        }
    
        return null;
      };
    }
    

    Demo @ StackBlitz