Reputation: 103
I am having issues validating my confirm-pass field onBlur in Angular 7. In my case I have built multiple custom validators which work after the control has been made 'dirty', as well as a directive following Pascal Prechts tutorial which DOES work onBlur when field is only touched, but I would like a pure Reactive solution and Pascal's requires adding to the HTML.
Problem Example: Click into firstName field, immediately tab or click out - built-in required validator fires. Click into confirmPass field, immediately click or tab out; custom validator does NOT fire (even console-logs aren't showing). If you were to type any single character prior to tabbing or clicking out however every version I've made does work, at that point.
I have tried building a validator class with multiple static methods. Controls all used one method ('director') which checks the incoming fieldname and redirected appropriately. This returned an error map or null value directly instead of the function, and of course didn't work.
Next I tried Pascal Prechts tutorial; https://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html which worked as a directive - I had to type in equalValidator into the HTML however - which I do not want to do.
Finally I tried the Angular suggested function and another I found on StackOverflow, both of which return a function; which itself returns the error map or null.
The FormGroup
ngOnInit() {
this.regForm = this.fb.group({
firstName: ["", [Validators.required, Validators.minLength(2), Validators.maxLength(30)]],
lastName: ["", [Validators.required, Validators.minLength(2), Validators.maxLength(30)]],
email: ["", [Validators.required, Validators.email]],
password: ["", [Validators.required, Validators.minLength(8), Validators.maxLength(55)]],
confirmPass: ["", matchingInputsValidator],
}, { updateOn: 'blur' });
this.lgnForm = this.fb.group({
lgnEmail: ["", [Validators.required, Validators.email]],
lgnPass: ["", Validators.required]
}, { updateOn: 'blur' });
}
Pascals solution which works onBlur, but as a directive only
function validateEqualFactory(compare: string) : ValidatorFn {
return (c: FormControl) => {
// value of confirm password field
let v = c.value;
// value of compared field - in this case 'password'
let e = c.root.get(compare);
// Ternary operator -> return null if equal or error map if not equal/password does not exist
return (e && v === e.value) ? null : { misMatch: true };
};
}
@Directive({
selector: '[validateEqual][formControl],[validateEqual][formControlName]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
]
})
export class EqualValidator implements Validator {
validator: ValidatorFn;
constructor() {
this.validator = validateEqualFactory("password");
}
validate(c: FormControl) {
return this.validator(c);
}
}
And finally two of the most recent attempts I have made, the first being a variation of Angular documentations official recommendation
export function confirmPassVal(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} | null => {
console.log("Making it here 1", control);
const passCtrl = control.root.get('password');
console.log("Making it here 2: ", passCtrl);
return (passCtrl && passCtrl.value === control.value) ? null : {"misMatch" : true };
}
}
export const matchingInputsValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
let pass;
control.root.get('password') ? pass = control.root.get('password').value : pass = null;
let confirmPass = control.value;
return pass === confirmPass ? null : { misMatch: true };
}
I expect my function to run when the field is touched and/or dirty, but it is currently only running if the field is dirty. In an ideal world I would like to be able to extend the Validators or NG_VALIDATORS class with my own custom functions, purely from the FormBuilder declaration. At this point I believe it has something to do with multi-provider, and extending NG_VALIDATORS but....I'm not sure how to do this even if it is the case.
Upvotes: 2
Views: 5755
Reputation: 7254
Angular runs validators first time when FormControl
is created and then each time value changes in that FormControl
. When you just focus and blur the input there is no revalidation going on.
For required
fields it works like this: when you create FormControl
trough FormBuilder
it gets validated and the error is there from the start. It is just not visible because the input was not touched yet. For matchingInputsValidator
the error is not there, because both fields are same at the start, so when you touch the input, no error is shown.
What you need to do is to trigger validation on confirmPass
form control on your own whenever password
changes. One good place to do that is in valueChanges
subscription of password
form control.
this.password.valueChanges.subscribe(() => this.confirmPass.updateValueAndValidity());
Here you'll find updated stackblitz demo.
Upvotes: 5