Search code examples
angularionic4angular-reactive-formsangular-custom-validators

Password and Confirm Password match validation in ionic4 form


I have created a signup form in ionic4 with fields like first name, last name, email, password and confirm password.

I have added validations also like showing the fields are required if user left or touch the respective fields.

I wanted to add validations for password and confirm password. i.e if the password and confirm password mismatching error.

below is my code:

html file:

<ion-content>

  <div style="margin: 30px">
    <ion-title class="ion-text-center">Register</ion-title>

    <form [formGroup]="loginForm">
      <ion-item>
        <ion-label position="floating">First Name*</ion-label>
        <ion-input formControlName="fname" type="text"></ion-input>
      </ion-item>
      <div class="error-messages">
        <ng-container *ngFor="let error of error_messages.fname">
          <div class="error-message" *ngIf="loginForm.get('fname').hasError(error.type) && (loginForm.get('fname').dirty || loginForm.get('fname').touched)">
            {{ error.message }}
          </div>
        </ng-container>

      </div>
      <ion-item>
        <ion-label position="floating">Last Name*</ion-label>
        <ion-input formControlName="lname" type="text"></ion-input>
      </ion-item>
      <div class="error-messages">
        <ng-container *ngFor="let error of error_messages.lname">
          <div class="error-message" *ngIf="loginForm.get('lname').hasError(error.type) && (loginForm.get('lname').dirty || loginForm.get('lname').touched)">
            {{ error.message }}
          </div>
        </ng-container>

      </div>
      <ion-item>
        <ion-label position="floating">Email Id*</ion-label>
        <ion-input formControlName="email" type="text"></ion-input>
      </ion-item>
      <div class="error-messages">
        <ng-container *ngFor="let error of error_messages.email">
          <div class="error-message" *ngIf="loginForm.get('email').hasError(error.type) && 
        (loginForm.get('email').dirty || loginForm.get('email').touched)">
            {{ error.message }}
          </div>
        </ng-container>

      </div>

      <ion-item>
        <ion-label position="floating">Password*</ion-label>
        <ion-input formControlName="password" type="password"></ion-input>
      </ion-item>
      <div class="error-messages">
        <ng-container *ngFor="let error of error_messages.password">
          <div class="error-message" *ngIf="loginForm.get('password').hasError(error.type) && (loginForm.get('password').dirty || loginForm.get('password').touched)">
            {{ error.message }}
          </div>
        </ng-container>

      </div>
      <ion-item>
        <ion-label position="floating">Confirm Password*</ion-label>
        <ion-input formControlName="confirmpassword" type="password"></ion-input>
      </ion-item>
      <div class="error-messages">
        <ng-container *ngFor="let error of error_messages.confirmpassword">
          <div class="error-message" *ngIf="loginForm.get('confirmpassword').hasError(error.type) && (loginForm.get('confirmpassword').dirty || loginForm.get('confirmpassword').touched)">
            {{ error.message }}
          </div>
        </ng-container>

      </div>
      <br>
      <div>
        <ion-button [disabled]="!loginForm.valid" expand="full">Signup</ion-button>
      </div>

    </form>

  </div>

</ion-content>

.ts file:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';

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

  loginForm: FormGroup;

  error_messages = {
    'fname': [{
      type: 'required',
      message: 'First Name is required.'
    }, ],

    'lname': [{
      type: 'required',
      message: 'Last Name is required.'
    }],

    'email': [{
        type: 'required',
        message: 'Email is required.'
      },
      {
        type: 'minlength',
        message: 'Email length.'
      },
      {
        type: 'maxlength',
        message: 'Email length.'
      },
      {
        type: 'required',
        message: 'please enter a valid email address.'
      }
    ],

    'password': [{
        type: 'required',
        message: 'password is required.'
      },
      {
        type: 'minlength',
        message: 'password length.'
      },
      {
        type: 'maxlength',
        message: 'password length.'
      }
    ],
    'confirmpassword': [{
        type: 'required',
        message: 'password is required.'
      },
      {
        type: 'minlength',
        message: 'password length.'
      },
      {
        type: 'maxlength',
        message: 'password length.'
      }
    ],
  }

  constructor(
    public formBuilder: FormBuilder
  ) {
    this.loginForm = this.formBuilder.group({
      fname: new FormControl('', Validators.compose([
        Validators.required
      ])),
      lname: new FormControl('', Validators.compose([
        Validators.required
      ])),
      email: new FormControl('', Validators.compose([
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(30)
      ])),
      password: new FormControl('', Validators.compose([
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(30)
      ])),
      confirmpassword: new FormControl('', Validators.compose([
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(30)
      ])),
    })
  }

  ngOnInit() {}

}

Please help me how can I add validations for password and confirm password if entered are mismatching.


Solution

  • Just create a validator that accepts a FormGroup and returns an error if both these fields don't match.

    import { Component } from '@angular/core';
    import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      loginForm: FormGroup;
    
      error_messages = { ... }
    
      constructor(
        public formBuilder: FormBuilder
      ) {
        this.loginForm = this.formBuilder.group({
          fname: new FormControl('', Validators.compose([
            Validators.required
          ])),
          ...
          confirmpassword: new FormControl('', Validators.compose([
            Validators.required,
            Validators.minLength(6),
            Validators.maxLength(30)
          ])),
        }, { 
          validators: this.password.bind(this)
        });
      }
    
      ngOnInit() {
      }
    
      password(formGroup: FormGroup) {
        const { value: password } = formGroup.get('password');
        const { value: confirmPassword } = formGroup.get('confirmpassword');
        return password === confirmPassword ? null : { passwordNotMatch: true };
      }
    
    }
    

    UPDATE:

    And in your Template:

    <div class="container">
    
      <div style="margin: 30px">
        <h1 class="ion-text-center">Register</h1>
    
        <form [formGroup]="loginForm">
          <div class="form-group">
            <label>First Name*</label>
            <input class="form-control" formControlName="fname" type="text" />
          </div>
          <div class="error-messages">
            <ng-container *ngFor="let error of error_messages.fname">
              <div class="error-message" *ngIf="loginForm.get('fname').hasError(error.type) && (loginForm.get('fname').dirty || loginForm.get('fname').touched)">
                {{ error.message }}
              </div>
            </ng-container>
          </div>
    
          ...
    
          <div class="form-group">
            <label>Confirm Password*</label>
            <input class="form-control" formControlName="confirmpassword" type="password" />
          </div>
          <div class="error-messages">
            <ng-container *ngFor="let error of error_messages.confirmpassword">
              <div class="error-message" *ngIf="loginForm.get('confirmpassword').hasError(error.type) && (loginForm.get('confirmpassword').dirty || loginForm.get('confirmpassword').touched)">
                {{ error.message }}
              </div>
            </ng-container>
            <div class="error-message" *ngIf="!loginForm.get('confirmpassword').errors && loginForm.hasError('passwordNotMatch') && (loginForm.get('confirmpassword').dirty || loginForm.get('confirmpassword').touched)">
              Password and Confirm Password fields should match
            </div>
          </div>
    
          <button class="form-control btn btn-primary" [disabled]="!loginForm.valid">Signup</button>
        </form>
      </div>
    </div>
    

    Here's a Working Sample StackBlitz for your ref.