Reputation: 491
I am implementing a Change Password Screen In which i need to check the equality of Password and Confirm Password . so I am implementing a custom validation.
But I am getting some exception " matcher.isErrorState is not a function".Please find my code below and let me know what is missing from my side.
TypeScript File -
export class ChangePasswordComponent implements OnInit {
password :any;
confirmPassword:any;
form :any ;
constructor(fb: FormBuilder, private authService: AuthService, private router: Router) {
this.password = new FormControl('', [Validators.required,Validators.minLength(8) , Validators.maxLength(20), Validators.pattern(new RegExp("(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])"))]);
this.confirmPassword = new FormControl('', [Validators.required, Validators.minLength(8) , Validators.maxLength(20)]);
this.form = fb.group({
password :this.password ,
confirmPassword :this.confirmPassword
});
var that = this;
this.form.controls.confirmPassword.setValidators([this.cross(this.password)]);
}
cross( p) {
console.log("in cross");
console.log(p);
return null;
}
}
Html Component File -
<form [formGroup]="form" class="example-form" >
<mat-form-field style="width: 100%">
<input matInput placeholder="Enter your password" [type]="'password'" formControlName="password" required>
<mat-error *ngIf="form.controls.password.invalid">{{validatePassword()}}</mat-error>
</mat-form-field>
<br>
<br>
<mat-form-field style="width: 100%">
<input matInput placeholder="Confirm your password" [type]="'password'" formControlName="confirmPassword" required>
<mat-error *ngIf="form.controls.confirmPassword.invalid">{{validateConfirmPassword()}}</mat-error>
</mat-form-field>
<br>
<button color="primary" (click)="changePassword()" [disabled]="!(form.controls.confirmPassword.valid || form.controls.password.valid)" mat-raised-button>Submit</button>
</form>
Upvotes: 0
Views: 10278
Reputation: 141
you are essentially validating how 2 fields in a form interact with each other ("password" and "confirm password" fields). This is known as "cross-field validation"
that means, your custom validator cannot be assigned to just 1 field. The custom validator needs to be assigned to the common parent, the form.
Here is the official documented best practice, for validating how 2 fields in a form interact with each other
https://angular.io/guide/form-validation#cross-field-validation
this code snippet worked for me
template:
<form method="post" [formGroup]="newPasswordForm">
<input type="password" formControlName="newPassword" />
<input type="password" formControlName="newPasswordConfirm" />
<div class="err-msg" *ngIf="newPasswordForm.errors?.passwordMismatch && (newPasswordForm.touched || newPasswordForm.dirty)">
confirm-password does not match password
</div>
</form>
component.ts:
export class Component implements OnInit {
this.newPasswordForm = new FormGroup({
'newPassword': new FormControl('', [
Validators.required,
]),
'newPasswordConfirm': new FormControl('', [
Validators.required
])
}, { validators: passwordMatchValidator });
}
export const passwordMatchValidator: ValidatorFn = (formGroup: FormGroup): ValidationErrors | null => {
return formGroup.get('newPassword').value === formGroup.get('newPasswordConfirm').value ?
null : { 'passwordMismatch': true };
}
Note that for passwordMatchValidator
, it is outside the component class. It is NOT inside the class
Upvotes: 0
Reputation: 188
Create custom directive equal-validator.directive.ts
import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidatorDirective), multi: true }
]
})
export class EqualValidatorDirective {
constructor( @Attribute('validateEqual') public validateEqual: string) {}
validate(c: AbstractControl): { [key: string]: any } {
// self value (e.g. retype password)
let v = c.value;
// control value (e.g. password)
let e = c.root.get(this.validateEqual);
// value not equal
if (e && v !== e.value) return {
validateEqual: false
}
return null;
}
}
Html (use validateEqual="password" in Confirm password field )
<form class="login-form" (ngSubmit)="onSubmit(f)" #f="ngForm">
<div class="col-lg-12 header">
Member Register
</div>
<div class="form-group">
<div class="col-lg-12">
<mat-form-field class="example-full-width">
<input type="password" matInput placeholder="Password" name="password" [(ngModel)]="user.password" #password="ngModel" required
minlength="8" maxlength="20" pattern="((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{8,20})">
</mat-form-field>
</div>
<div class="col-lg-12">
<mat-error *ngIf="password.touched">
<mat-error *ngIf="password.errors?.required">
Password is
<strong>required</strong>
</mat-error>
<mat-error *ngIf="password.errors?.pattern">
Password is
<strong>Invalid</strong>
</mat-error>
</mat-error>
</div>
</div>
<div class="form-group">
<div class="col-lg-12">
<mat-form-field class="example-full-width">
<input type="password" matInput placeholder="Confirm Password" name="confirmPassword" [(ngModel)]="user.confirmPassword"
#confirmPassword="ngModel" required validateEqual="password">
</mat-form-field>
</div>
<div class="col-lg-12">
<mat-error *ngIf="confirmPassword.touched">
<mat-error *ngIf="confirmPassword.errors?.required">
Confirm Password is
<strong>required</strong>
</mat-error>
<mat-error *ngIf="!(confirmPassword.valid || confirmPassword.pristine)">
Password amd Confirm Password is
<strong>Not matched</strong>
</mat-error>
</mat-error>
</div>
</div>
<div class="form-group">
<div class="col-lg-12">
<button mat-button [disabled]="f.invalid">Register</button>
</div>
<div class="col-lg-12">
<div class="center">
<mat-error>
{{messageText}}
</mat-error>
</div>
</div>
</div>
</form>
Upvotes: 0
Reputation: 2487
Check out this article , I think will provide you a good understanding how to do it https://scotch.io/@ibrahimalsurkhi/match-password-validation-with-angular-2
basically what you need to do is assign to de confirm password control a custom validator like this:
export const confirmValidator = (password: FormControl) =>
(confirmPassword: FormControl): ValidationErrors | null => {
// return a object with error type if there is some kind of error
// return null if there is no error
}
then you can use this validator by passing the password formControl when passed
this.form.get("confirmpassword").setValidators([confirmValidator(this.form.get("password"))])
try this and let me know
Upvotes: 2