Fahad Subzwari
Fahad Subzwari

Reputation: 2325

Custom password match validator is not working in angular5

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

Answers (3)

asim razzaq
asim razzaq

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

Muhammed Albarmavi
Muhammed Albarmavi

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

JB Nizet
JB Nizet

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

Related Questions