0

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>
4
  • your are receiving this error on page loaded or when you modify the form? Commented Mar 2, 2018 at 13:10
  • @Ricardo , I am getting exception on page loaded Commented Mar 2, 2018 at 13:26
  • I think you have some issue with the regular expression Commented Mar 2, 2018 at 13:27
  • @Ricardo no i don't think there is some issue with regex that is working fine. Commented Mar 2, 2018 at 15:08

3 Answers 3

2

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

Sign up to request clarification or add additional context in comments.

5 Comments

check the template... I m pretty sure is a dummy character
I have figured out "v is not a function" but now i am unable to pass any parameter to confirmValidator function.
please refer updated code and i am getting exception is " TypeError: Cannot read property 'validate' of null TypeError: Cannot read property 'validate' of null at normalizeValidator (forms.js:1076) at Array.map (<anonymous>) at composeValidators (forms.js:2439) at coerceToValidator (forms.js:2843) at FormControl.AbstractControl.setValidators (forms.js:3079) at new ChangePasswordComponent (change-password.component.ts:29)" Line now 29 is " this.form.controls.confirmPassword.setValidators([this.cross(this.password)]);"
this.password === this.form.controls.password , no?, because if no, then the method that I propose to you it wont work because is specting a formControl
I have figured out the validation part and it is working now also. but i am missing one part that is displaying error message from custom validation .I can see this is coming as undefined in custom validator function
0

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>

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.