Reputation: 2325
I am implementing custom validator to match password in my component.
Here is my component.ts form declaration
this.addUserForm = new FormGroup({
firstname: new FormControl('', [Validators.required]),
lastname: new FormControl('', [Validators.required]),
city: new FormControl(),
address: new FormControl(),
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.minLength(6)]),
confirm_password: new FormControl('', [Validators.required, ConfirmPasswordValidator.MatchPassword]),
role: new FormControl('', [Validators.required]),
phone: new FormControl(),
companyCode: new FormControl(this.local_storage.getCurrentUser().companyCode, [Validators.required])
});
here is my custom.validator.ts
import { AbstractControl } from '@angular/forms';
export class ConfirmPasswordValidator {
static MatchPassword(control: AbstractControl) {
let password = control.get('password').value;
let confirmPassword = control.get('confirm_password').value;
if (password != confirmPassword) {
console.log('false')
control.get('confirmPassword').setErrors({ ConfirmPassword: true });
} else {
return null
}
}
}
Here is my component.html input part
<label class="col-form-label">Password</label>
<div class="form-group row">
<div class="col-sm-10">
<input type="password" class="form-control" formControlName="password">
<div class="alert alert-danger" *ngIf="addUserForm.get('password').touched && addUserForm.get('password').invalid && addUserForm.get('password').errors.required">
Password is required
</div>
<div class="alert alert-danger" *ngIf="addUserForm.get('password').touched && addUserForm.get('password').invalid && addUserForm.get('password').errors.minlength && !addUserForm.get('password').errors.required">
Password length must be greater than 6
</div>
</div>
</div>
<div class="alert alert-danger" *ngIf="addUserForm.get('confirm_password').touched && addUserForm.get('confirm_password').invalid && addUserForm.get('confirm_password').errors.ConfirmPassword">
Password deesn't match
</div>
But it is giving this error
property 'value' of null TypeError: Cannot read property 'value' of null at ConfirmPasswordValidator.MatchPassword (user.validator.ts:5)
Project structure and directory is very complex and huge that's why can't share all component and html code.
What's wrong in my code?
Upvotes: 2
Views: 2049
Reputation: 3
registerForm = new FormGroup({
username : new FormControl(),
password : new FormControl(),
confirmPassword : new FormControl(null,matchValues["password"])
);
Every time the user types into the Password field, it wil the run the validator in the Confirm Password field:
registerForm.controls['password'].valueChanges.subscribe({
next: (_) =>
registerForm.controls['confirmPassword'].updateValueAndValidity(),
});
Validator Function
matchValues(matchTo: string): ValidatorFn {
return (control: AbstractControl) => {
return control.value === control.parent?.get(matchTo)?.value
? null
: { isMatching: true };
};
}
Upvotes: 0
Reputation: 24406
Form Group Validator
Update MatchPassword
to work on form group level so you don't need to add a custome validator to confirmPassword
control
static MatchPassword(control: AbstractControl) {
let password = control.get('password').value;
let confirmPassword = control.get('confirm_password').value;
if (password != confirmPassword) {
return { ConfirmPassword: true };
} else {
return null
}
}
and add this validator for formGroup validators options
{ validators: ConfirmPasswordValidator.MatchPassword }
stackblitz demo 🚀🚀
Form Control Validator
if you want to add the validation to the control so the control parameter will be confirm password control and you need to use parent to access to the form group and get the value of password control
this.form = fb.group({
password: [null, [Validators.required]],
confirm_password: [null, [Validators.required, MatchPassword]]
})
MatchPassword validator
function MatchPassword(control: AbstractControl) {
let parent = control.parent
if (parent) {
let password = parent.get('password').value;
let confirmPassword = control.value;
if (password != confirmPassword) {
return { ConfirmPassword: true };
} else {
return null
}
} else {
return null;
}
stackblitz demo 🚀🚀
Upvotes: 1
Reputation: 691625
There are several problems with your code.
First: You're getting a child from control named 'password' and another child form control named 'confirmPassword' from the control passed to the validator. So what the validator is supposed to validate is a FormGroup
, containing these two form controls. But you're not setting this validator on the form group. You're setting it on the form control confirmPassword
. You need to set this validator on the enclosing form group.
Second: a validator is not supposed to modify the control it is validating. Its sole responsibility is to return the error(s) (or null if there is no error). Angular will set the validity of the control based on what you return. So its code should be
static MatchPassword(control: AbstractControl) {
const password = control.get('password').value;
const confirmPassword = control.get('confirm_password').value;
if (password != confirmPassword) {
return { ConfirmPassword: true };
} else {
return null;
}
}
Or, written more concisely:
static MatchPassword(control: AbstractControl) {
return control.get('password').value != control.get('confirm_password').value ? { ConfirmPassword: true } : null;
}
Upvotes: 1