How to display max length based on FormControl’s validator

Unfortunately `hasValidator` does not work well with validators created dynamically like `Validator.maxLength` but there is a solution that allows getting information about maxLength value anyway.

You can view the source code for this project by following this link: GitHub

Demo

Take a look at the title hint. Try to provide a title longer than 15 chars.

Problem with hasValidator

Let’s create a simple FormControl with maxLength validator. To check if the control has some validator we can use the hasValidator method but it does not work correctly for Validators.maxLength(15) because calling Validators.maxLength(15) creates another reference and the implementation of hasValidator check validators by reference.

import { FormControl, Validators } from "@angular/forms";

const titleControl = new FormControl(null, [Validators.maxLength(15)]);
titleControl.hasValidator(Validators.maxLength(15)); // -> false

// ---

const max15Chars = Validators.maxLength(15);
const titleControl = new FormControl(null, [max15Chars]);
titleControl.hasValidator(max15Chars); // -> true

Checking if a control has a maxLength validator without hasValidator

To check if the control has a maxLength validator let’s first take a look into maxLength implementation.

//  The fragment of maxLength validator
export function maxLengthValidator(maxLength: number): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    return hasValidLength(control.value) && control.value.length > maxLength
      ? { maxlength: { requiredLength: maxLength, actualLength: control.value.length } }
      : null;
  };
}

// ---

function hasValidLength(value: any): boolean {
  return value != null && typeof value.length === "number";
}

As you can see validator checks if a control’s value has a valid length (if it is an object with a length property) and then compares this length with maxLength argument.

We can use this knowledge to create a fake object with a length property. We can get all control’s validators and check if we get the maxLength error for { length: Infinity }.

import { AbstractControl, FormControl, Validators } from "@angular/forms";

function hasMaxLengthValidator(control: AbstractControl): boolean {
  const validator = control.validator;

  if (validator === null) {
    return false;
  }

  const errors = validator(new FormControl({ length: Infinity })) ?? {};
  return "maxlength" in errors;
}

const titleControl = new FormControl(null, [Validators.maxLength(15)]);
const hasMaxLengthValidator = hasMaxLengthValidator(titleControl);
console.log(hasMaxLengthValidator); //-> true

Because nothing can be bigger than Infinity we are sure that we cause an error if the validator contains maxLength validator.

Getting maxLength value from the validator

To get information about the maxLength value from the validator first we need to cause an error. In the error details, we have information about the maxLength value and actual value of a control.

import { AbstractControl, FormControl, Validators } from "@angular/forms";

function getMaxLengthFromValidator(control: AbstractControl, fallback: number): number;
function getMaxLengthFromValidator(control: AbstractControl): number | undefined;
function getMaxLengthFromValidator(control: AbstractControl, fallback?: number): number | undefined {
  const validatorFn = control.validator;

  if (validatorFn === null) {
    return fallback;
  }

  const errors = validatorFn(new FormControl({ length: Infinity }));
  return errors?.["maxlength"]["requiredLength"] ?? fallback;
}

const titleControl = new FormControl(null, [Validators.max(15)]);
const maxLengthValue = getMaxLengthFromValidator(titleControl);
console.log(maxLengthValue); //-> 15

Do you like the content?

Your support helps me continue my work. Please consider making a donation.

Donations are accepted through PayPal or Stripe. You do not need a account to donate. All major credit cards are accepted.

Leave a comment