Validating Passwords with Angular Reactive Forms | Task

Ole Ersoy
Jan - 14  -  2 min

Scenario

On our registration form we have a password field and a confirmPassword field.

We want to validate that the confirmPassword field matches the password field prior to enabling the submit button for the form.

If the passwords do not match then the mat-error notification below the confirmPassword field will display a message indicating this.

Approach

Matching the Passwords

First within our validation.service.ts service we will create a factory function used to produce the ValidatorFn instance that will check whether the passwords match.

  passwordMatch(password: string, confirmPassword: string): ValidatorFn {
    return (formGroup: AbstractControl): { [key: string]: any } | null => {
      const passwordControl = formGroup.get(password);
      const confirmPasswordControl = formGroup.get(confirmPassword);

      if (!passwordControl || !confirmPasswordControl) {
        return null;
      }

      if (
        confirmPasswordControl.errors &&
        !confirmPasswordControl.errors.passwordMismatch
      ) {
        return null;
      }

      if (passwordControl.value !== confirmPasswordControl.value) {
        confirmPasswordControl.setErrors({ passwordMismatch: true });
        return { passwordMismatch: true };
      } else {
        confirmPasswordControl.setErrors(null);
        return null;
      }
    };
  }

If the there are no errors then null is returned. If the passwords do no match we set the passwordMismatch error on the confirmPasswordControl.

Creating the Reactive Form

Note that the passwordMatch function is passed in as the second argument in the FormGroup constructor:

public registrationForm: FormGroup = new FormGroup(
  {
    password: new FormControl('', [
      Validators.required,
      Validators.minLength(8),
      Validators.maxLength(32),
      this.v.passwordMinLowerCaseLettersValidator(),
    ]),
    confirmPassword: new FormControl(
      '',
      Validators.compose([Validators.required])
    ),
  },
  this.v.passwordMatch('password', 'confirmPassword')
);

Creating the Reactive Form Template

<mat-card style="min-width: 10rem; max-width:30rem;margin: 2rem;">
  <form
    fxLayoutAlign="stretch"
    fxLayout="column"
    [formGroup]="registrationForm"
    (ngSubmit)="submit()"
  >
    <mat-form-field>
      <input
        matInput
        type="password"
        placeholder="Password"
        formControlName="password"
      />
      <mat-hint *ngIf="!passwordValue">Example @123PASSWord</mat-hint>
      <mat-error *ngIf="passwordControl.invalid">{{
        getPasswordError()
      }}</mat-error>
    </mat-form-field>
    <mat-form-field>
      <input
        matInput
        type="password"
        placeholder="Confirm Password"
        formControlName="confirmPassword"
      />
      <mat-error *ngIf="confirmPasswordControl.invalid"
        >Passwords do not match
      </mat-error>
    </mat-form-field>

    <button mat-button type="submit" [disabled]="!registrationForm.valid">
      Register
    </button>
  </form>
</mat-card>

Demo