Sun
Sun

Reputation: 4708

Get validators and values from angular FormControl

Is there a way for find out if an Angular FormControl has a validator and its value?

e.g. If I had a form control setup like this:

testControl: new FormControl(null, [Validators.required, Validators.minLength(5), Validators.maxLength(20)]),

Could I then check if the form control had the MaxLength validator, and more importantly, could I get out the maximum value.

I can do the following for the required validator:

const isRequired  = this.formCtrl.hasValidator(Validators.required);

But how do I get the MaxValidator and its value.

Thanks

Upvotes: 0

Views: 602

Answers (4)

Rashmi Yadav
Rashmi Yadav

Reputation: 79

To achieve what you are asking for, you can do something like this:

getValidatorConfig(validator: any) {
    return validator ? validator(this.testControl)?.[validator.length === 1 ? 'requiredLength' : 'max'] : null;
  }

  ngOnInit() {
    const hasRequired = this.testControl.hasValidator(Validators.required);
    const hasMaxLength = this.testControl.hasValidator(Validators.maxLength);
    const maxLengthValue = this.getValidatorConfig(Validators.maxLength);

    console.log('Has Required Validator:', hasRequired);
    console.log('Has MaxLength Validator:', hasMaxLength);
    console.log('MaxLength Value:', maxLengthValue);
  }

Hope it helps!

Upvotes: 0

Shlang
Shlang

Reputation: 3230

There is no official public API for doing this. Moreover, since Validators are just functions you cannot get what was passed to e.g. Validator.min as this value is inside a closure.

But, there is a private property _rawValidators on the FromControl, that contains all the validators. Again, it is not very useful, because it is just an array of anonymous functions distinguishable only by reference and it is pretty much the same thing hasValidator offers.

There is a workaround. Since Validators are just functions and functions in JS may have properties, you can create a bunch of wrappers around Angular's validators that would have the information you need, for example:

export const MyValidators = {
  min: (value: number) => {
    const ngValidator = Validators.min(value) as MyValidator<number>;
    ngValidator.meta = {
      type: 'min',
      value,
    };
    return ngValidator;
  },
};

Then you can access them via _rawValidators and see this metadata.

Going further, you're right if you don't like the idea of using a private property. What is possible to do is extend FormControl with a public property that contains validators, unfortunately in the latest versions FC constructor is defined in a quite a fancy way so TS gets crazy and does not let to do it easily keeping all the type safety, but the main idea is something like this:

export function myFormControl<TValue = any>(
  formState: FormControlState<TValue> | TValue = null as unknown as TValue,
  validatorOrOpts?: ValidatorFn | ValidatorFn[] | FormControlOptions | null,
  asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null
): FormControl<TValue> & { myValidators: ValidatorFn[] | null } {
  const fc = new FormControl(formState, validatorOrOpts, asyncValidator);

  const validators = pickValidators(validatorOrOpts);

  const myFc = fc as FormControl<TValue> & {
    myValidators: ValidatorFn[] | null;
  };
  myFc.myValidators =
    validators === null
      ? null
      : Array.isArray(validators)
        ? validators
        : [validators];

  return myFc;
}

I created a repl with working example here

Upvotes: 1

danielk97
danielk97

Reputation: 31

To check if control has validator which is called with some parameters you must refer to exact the same validator both in control and in hasValidator():

const maxValidator = Validators.max(17);
const testControl = new FormControl('', [maxValidator]);
console.log(testControl.hasValidator(maxValidator)); // true

To not create validator for each control separatly you could create a wrapper for validators:

class ValidatorsWrapper {
  static maxValidators = new Map<number, ValidatorFn>();

  static max(max: number) {
    if(!this.maxValidators.has(max)) {
      this.maxValidators.set(max, Validators.max(max));
    }
    return this.maxValidators.get(max)!;
  }
}

const testControl = new FormControl('', [ValidatorsWrapper.max(15)]);
console.log(testControl.hasValidator(ValidatorsWrapper.max(15))); // true
console.log(testControl.hasValidator(ValidatorsWrapper.max(64))); // false

Hope this help.

Upvotes: 0

Mehmet S
Mehmet S

Reputation: 349

When maxLength is invalid, you can get the requiredLength value as follows;

this.form.get('testControl')?.errors?.['maxlength']

Upvotes: 0

Related Questions