I'm trying to validate a form using custom validation. For some reason I have to build a form that can change either E-Mail or set a new Password. For that reason I cannot use Validators.required as password fields become only required when they are touched.
My problem is that when input validation is resolved the form is still invalid.
I've made a plnkr to demonstrate my problem:
http://plnkr.co/edit/obF4gC5RHkXOOlCEsIuH?p=preview
ngOnInit(): void {
this.emailField = new FormControl('[email protected]', Validators.email);
this.pw1 = new FormControl('', [this.passwordAreEqualValidator, Validators.minLength(2)]);
this.pw2 = new FormControl('', this.passwordAreEqualValidator);
this.pwOld = new FormControl('', this.notEmptyIfNewIsTouchedValidator);
this.form = this.formBuilder.group({
pw1: this.pw1,
pw2: this.pw2,
emailField: this.emailField,
pwOld: this.pwOld
});
}
notEmptyIfNewIsTouchedValidator(control: FormControl) : ValidationErrors | null {
if (control.dirty) {
if (control.value === '') {
return {
oldPasswordEmpty: true
}
}
const parent = control.parent,
pw1 = parent.get('pw1'),
pw2 = parent.get('pw2');
// this will trigger nothing in template, this part is only
// to mark form invalid if password was entered. passwordNew1
// cannot be false by default as this is okay when you only
// want to change your e-mail adress.
if (pw1.value.length === 0) {
pw1.setErrors({noPassword: true});
} else {
if (pw1.hasError('noPassword')) {
let pw1Errors = pw1.errors;
delete pw1Errors.noPassword;
pw1.setErrors(pw1Errors);
}
}
console.log('pw1 errors: ', pw1.errors);
console.log('pw2 errors: ', pw2.errors);
console.log('old errors: ', control.errors);
}
return null;
}
passwordAreEqualValidator(control: FormControl): ValidationErrors | null {
if (control.dirty) {
const
parent = control.parent,
pwOld = parent.get('pwOld'),
pw1 = parent.get('pw1'),
pw2 = parent.get('pw2');
if (pwOld.value === '') {
pwOld.setErrors({oldPasswordEmpty: true})
}
if (pw1.value !== pw2.value) {
return {
notEqual: true
};
} else {
let pw1Errors = pw1.errors;
if (pw1.hasError('notEqual')) {
delete pw1Errors.notEqual;
pw1.setErrors(pw1Errors);
}
if (pw1.hasError('noPassword')) {
delete pw1Errors.noPassword;
pw1.setErrors(pw1Errors);
}
pw2.setErrors(null);
console.log('pw1 errors: ', pw1.errors);
console.log('pw2 errors: ', pw2.errors);
console.log('old errors: ', pwOld.errors);
}
}
return null;
}
Steps to reproduce:
Why is my form invalid?
P.S: Once I edit my pw1 again, my form becomes valid, although the result of the errors did not change.
When the user changes the value in the watched field, the control is marked as "dirty" When the user blurs the form control element, the control is marked as "touched"
The difference between touched and dirty is that with touched the user doesn't need to actually change the value of the input control. touched is true of the field has been touched by the user, otherwise it's false. The opposite of touched is the property untouched .
You have the Validator set on both fields..... what happens is that pw1 does not revalidate when you enter pw2, so pw1 is still invalid until you go back and type it in again.
In your component, at the end of your ngOnInit, you can add the following....
this.pw1.valueChanges().subscribe(() => this.pw2.updateValueAndValidity());
this.pw2.valueChanges().subscribe(() => this.pw1.updateValueAndValidity());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With