multiple custom validators in reactive form angular 2

Paridokht picture Paridokht · Sep 9, 2017 · Viewed 10.2k times · Source

I have two custom validator in a reactive form, I call function below to create form in component constructor:

private createForm(): void {
this.passwordUpdateForm = this.formBuilder.group({
    newpassword : [null, Validators.required],
    passwordconfirm: [null, Validators.required]
},
{
    validator: [PasswordValidation.PasswordMatch, PasswordValidation.PasswordRule] // validation method

});

}

PasswordValidation is a class with two functions like below

    export class PasswordValidation {

     public  static PasswordMatch(control: AbstractControl) {
        let password = control.get('newpassword'); // to get value in input tag
        if(password){
            let confirmPassword = control.get('passwordconfirm').value; // to get value in input tag
            if (password.value !== confirmPassword) {
                control.get('passwordconfirm').setErrors({ ['passwordmatch'] : true});
            }else {
                return null;
            }
        }
    }

    public static PasswordRule(control: AbstractControl) {
        let password = control.get('newpassword').value; // to get value in input tag
        let pattern = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,64}');               
        if (!pattern.test(password)) {
            control.get('newpassword').setErrors({ ['passwordrule'] : true});
        }else if (password.toLowerCase() === 'something') {
            control.get('newpassword').setErrors({ ['passwordrule'] : true});
        }else {
            return null;
        }
    }
}

each custom validator works fine separately like this

validator: PasswordValidation.PasswordMatch

or this

validator: PasswordValidation.PasswordRule

but using both of them in array like

validator: [PasswordValidation.PasswordMatch, PasswordValidation.PasswordRule]

get error this.validator is not a function and does not work, I do not have any idea, please help.

Answer

Niladri picture Niladri · Sep 9, 2017

its better to use Validators.compose([]) which accepts the array of validators to be used on the specific user control in the form group.

for example if you want to add the validators against the passwordconfirm and newpassword control you can do it like below

private createForm(): void {
this.passwordUpdateForm = this.formBuilder.group({
    newpassword : [null, Validators.compose([Validators.required,PasswordValidation.PasswordRule])],
    passwordconfirm: [null, Validators.compose([Validators.required, PasswordValidation.PasswordMatch])]
});

under the hood this is what the code looks like

group(controlsConfig: {[key: string]: any}, extra: {[key: string]: any} = null): FormGroup {
  const controls = this._reduceControls(controlsConfig);
  const validator: ValidatorFn = isPresent(extra) ? extra['validator'] : null;
  const asyncValidator: AsyncValidatorFn = isPresent(extra) ? extra['asyncValidator'] : null;
  return new FormGroup(controls, validator, asyncValidator);
}

you can see the paramater validator is actually a type of interface ValidatorFn which looks like below

interface ValidatorFn { 
  (c: AbstractControl): ValidationErrors|null
}

so you can see it can accept any method that has the above signature.

Source : https://angular.io/api/forms/ValidatorFn

Check this link for more : https://toddmotto.com/reactive-formgroup-validation-angular-2