Thursday, 19 October 2023

How do I make a password match custom validator show an error message on the password field in Angular 16?

I am working on a reactive registration form in Angular 16.

I have made a custom validation to check if the values in the form fields password and confirm_password match:

import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";

export const matchpassword : ValidatorFn = (control: AbstractControl):ValidationErrors|null => {

     let password = control.get('password');
     let confirm_password = control.get('confirm_password');
     if (password && confirm_password && password?.value != confirm_password?.value) {
        return { password_match : true }
     }
    return null; 
}

In components\registration\registration.component.ts I have:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { matchpassword } from "../../custom-validators/matchpassword.validator";

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.scss']
})
export class RegistrationComponent implements OnInit {

  public registrationForm!: FormGroup;
  public isSuccess: Boolean = false;

  constructor(private formBuilder: FormBuilder) { }

  get form() { return this.registrationForm.controls }

  public registerUser() {

    if (this.registrationForm.status !== 'INVALID') {
      // Show success alert
      this.isSuccess = true;

      // Reset form
      this.registrationForm.reset();
    } else {
      return;
    }
  }

  ngOnInit() {
    this.registrationForm = this.formBuilder.group({
      firstName: ['', [Validators.required, Validators.minLength(3)]],
      lastName: ['', [Validators.required, Validators.minLength(3)]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(6), matchpassword]],
      confirm_password: ['', matchpassword],
      terms: ['', Validators.requiredTrue],
    }, {
      validators: matchpassword
    });
  }
}

In components\registration\registration.component.html I have:

<div *ngIf="isSuccess" class="alert alert-success alert-dismissible fade show text-center">
    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    Your signup was successful!
</div>

<form [formGroup]="registrationForm" (ngSubmit)="registerUser()" novalidate>
    <div class="form-element mb-2">
      <label for="firstName" class="form-label">
        First name
      </label>
      <input type="text" id="firstName" formControlName="firstName" class="form-control form-control-sm" />
      <span class="invalid-feedback" *ngIf="form['firstName']?.touched && form['firstName'].errors?.['required']">The <i>First name</i> field is
        required</span>
    </div>

    <div class="form-element mb-2">
      <label for="lastName" class="form-label">
        Last name
      </label>
      <input type="text" id="lastName" formControlName="lastName" class="form-control form-control-sm" />
      <span class="invalid-feedback" *ngIf="form['lastName'].touched && form['lastName'].errors?.['required']">The <i>Last name</i> field is
        required</span>
    </div>

    <div class="form-element mb-2">
      <label for="email" class="form-label">
        Email address
      </label>
      <input type="email" id="email" formControlName="email" class="form-control form-control-sm" />
      <span class="invalid-feedback" *ngIf="form['email'].touched && form['email'].errors?.['required']">The <i>Email</i> field is
        required</span>
      <span class="invalid-feedback" *ngIf="form['email'].touched && form['email'].errors?.['email']">Please provide a valid email
        address</span>

    </div>

    <div class="form-element mb-2">
      <label for="password" class="form-label">
        Password
      </label>
      <input type="password" id="password" formControlName="password" class="form-control form-control-sm" />
      <span class="invalid-feedback" *ngIf="form['password'].touched && form['password'].errors?.['required']">The <i>Password</i> field is
        required</span>
      <span class="invalid-feedback" *ngIf="form['password'].touched && form['password'].errors?.['minlength']">The password must have al least 6 characters</span>
      <span class="invalid-feedback" *ngIf="form['password'].touched && form['password'].errors?.['password_match']">The passwords do not match</span>
    </div>

    <div class="form-element mb-2">
      <label for="confirm_password" class="form-label">
        Confirm password
      </label>
      <input type="password" id="confirm_password" formControlName="confirm_password"
        class="form-control form-control-sm" />
    </div>

    <div class="form-element mb-2">
      <input type="checkbox" formControlName="terms" id="terms" class="me-1">
      <span class="text-terms text-muted">I accept the <a href="#" class="text-success">Terms & conditions</a></span>
      <span class="invalid-feedback terms" *ngIf="form['terms'].dirty && form['terms'].errors?.['required']">You must accept our Terms &
        conditions</span>
    </div>

    <div class="pt-2">
      <button type="submit" class="btn btn-sm btn-success w-100" [disabled]="!registrationForm.valid">
        Submit
      </button>
    </div>
</form>

The goal

If the passwords do not match, I want the error message "The passwords do not match" to show on the password field, as below:

What I want

The problem

Although the password is seen as invalid (the submit button is disabled), the error message does not show:

What is happening

What am I doing wrong?



from How do I make a password match custom validator show an error message on the password field in Angular 16?

No comments:

Post a Comment