Search code examples
javascriptangularvalidationangular-materialangular-material-stepper

add custom validation in input type text using angular material stepper


I am using angular stepper to display all my data and take input for some of the text boxes, but I want to add my custom validations when user clicks on Next button.

stackblitz - material-stepper-custom-validation

html:

<mat-horizontal-stepper #stepper>
  <mat-step>
    <div class="m-10">
      <input type="text" id="fname" placeholder="First Name" >
      </div>
      <div class="m-10">
      <input type="text" id="lname" placeholder="Last Name" >
      </div>
      <div>
        <button mat-button (click)="checkData()" matStepperNext>Next</button>
      </div>
  </mat-step>
  <mat-step [stepControl]="secondFormGroup" [optional]="isOptional">
        <button mat-button matStepperPrevious>Back</button>
        <button mat-button matStepperNext>Next</button>      
  </mat-step>
  <mat-step>
    <ng-template matStepLabel>Done</ng-template>
    You are now done.
    <div>
      <button mat-button matStepperPrevious>Back</button>
      <button mat-button (click)="stepper.reset()">Reset</button>
    </div>
  </mat-step>
</mat-horizontal-stepper>

Here, first name and last name should be validated before go to next stepper, but not using formGroup.

ts:

import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
@Component({
  selector: 'stepper-optional-example',
  templateUrl: 'stepper-optional-example.html',
  styleUrls: ['stepper-optional-example.css']
})
export class StepperOptionalExample implements OnInit {

  constructor() {}

  ngOnInit() { }

  checkData() {    
    let lname = (<HTMLInputElement>document.getElementById("fname")).value;
    if(lname == '') {
      alert('error');
    }
    return false;
  }
}

How? - If first name is empty then don't allow them to go Next stepper.


Solution

  • Because you use the template driven approach, you will need to map all input fields into an ngModel somehow. Here is an example for it:

    HTML:

    <input type="text" required [(ngModel)]="model.name" name="name">
    

    TS:

    @Component({
      selector: 'stepper-optional-example',
      templateUrl: 'stepper-optional-example.html',
      styleUrls: ['stepper-optional-example.css']
    })
    export class StepperOptionalExample implements OnInit {
    
      @ViewChild('stepper') stepper;
    
      model = {
        name: 'Initial Value'
      }
    
      constructor() {}
    
      ngOnInit() { }
    
    }
    

    Using that you can then, check the attribute onClick. You need to remove the matStepperNext and add the (click) event listener instead like so:

    HTML:

    <button mat-button (click)="onNext()">Next</button>
    

    TS:

    onNext() {
      // Validate your value in the function
      if (this.model.name !== 'Henry') {
        this.stepper.next();
      }
    }
    

    Other than that I also recommend to take a look on the official guide showing how to implement the template driven approach: https://angular.io/guide/forms