Custom Validator on reactive form for password and confirm password matching getting undefined parameters into Angular 4

import {AbstractControl, FormBuilder, FormGroup, Validators} from

set your password input into the group and no need to use "ngModel".

<div class="form-group row" formGroupName="passwords">
  <div class="form-group">
     <label for="password" class="control-label">Contraseña:</label>
     <input type="password" class="form-control" formControlName="password" title="Please enter your password">
     <p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contraseña</p>
  </div>
  <div class="form-group">
     <label for="confirmedPassword" class="control-label">Confirmar Contraseña:</label>
     <input type="password" class="form-control" formControlName="confirmedPassword"  title="Please re-enter your password">
     <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">Password must be required</p>
     <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">password does not match</p>
  </div>

     buildForm(): void {
            this.userForm = this.formBuilder.group({
                passwords: this.formBuilder.group({
                    password: ['', [Validators.required]],
                    confirm_password: ['', [Validators.required]],
                }, {validator: this.passwordConfirming}),

            });
        }

add this custom function for validate password and confirm password

  passwordConfirming(c: AbstractControl): { invalid: boolean } {
    if (c.get('password').value !== c.get('confirm_password').value) {
        return {invalid: true};
    }
}

Display error when password does not match

<div style='color:#ff7355' *ngIf="userForm.get(['passwords','password']).value != userForm.get(['passwords','confirm_password']).value && userForm.get(['passwords','confirm_password']).value != null">
  Password does not match</div>

The issue is that you are mixing the reactive forms module with the input approach. This is causing you to get undefined when passing the values to the validator.

You don't need to bind to the ng-model when using the reactive forms. Instead, you should access the value of the fields from the Instance of FormGroup.

I do something like this in an app to validate the passwords match.

public Credentials: FormGroup;

ngOnInit() {
    this.Credentials = new FormGroup({});
    this.Credentials.addControl('Password', new FormControl('', [Validators.required]));
    this.Credentials.addControl('Confirmation', new FormControl(
        '', [Validators.compose(
            [Validators.required, this.validateAreEqual.bind(this)]
        )]
    ));
}

private validateAreEqual(fieldControl: FormControl) {
    return fieldControl.value === this.Credentials.get("Password").value ? null : {
        NotEqual: true
    };
}

Note that the validator expects a FormControl field as a parameter and it compares the value of the field to that of the value of the Password field of the Credentials FormGroup.

In the HTML make sure to remove the ng-model.

<input type="password" class="form-control" formControlName="confirmedPassword"  title="Please re-enter your password" >
<!-- AND -->
<input type="password" class="form-control" formControlName="password" title="Please enter your password">

Hope this helps!


There are two types of validators: FormGroup validator and FormControl validator. To verify two passwords match, you have to add a FormGroup validator. Below is my example:

Note: this.fb is the injected FormBuilder

this.newAccountForm = this.fb.group(
  {
    newPassword: ['', [Validators.required, Validators.minLength(6)]],
    repeatNewPassword: ['', [Validators.required, Validators.minLength(6)]],
  }, 
  {validator: this.passwordMatchValidator}
);

passwordMatchValidator(frm: FormGroup) {
  return frm.controls['newPassword'].value === frm.controls['repeatNewPassword'].value ? null : {'mismatch': true};
}

and in the templeate:

<div class="invalid-feedback" *ngIf="newAccountForm.errors?.mismatch && (newAccountForm.controls['repeatNewPassword'].dirty || newAccountForm.controls['repeatNewPassword'].touched)">
  Passwords don't match.
</div>

The key point here is to add the FormGroup validator as the second parameter to the group method.