0

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.

Pathik Vejani
  • 4,263
  • 8
  • 57
  • 98
  • 3
    I recommend you have a look at [Reactive Forms](https://angular.io/guide/reactive-forms). Also this `(document.getElementById("fname")).value` is 100% not done when using Angular. – Giovani Vercauteren Dec 09 '19 at 08:26
  • Is that possible without reactive forms? – Pathik Vejani Dec 09 '19 at 08:28
  • @GiovaniVercauteren Also I have some typical view when uses enters information. – Pathik Vejani Dec 09 '19 at 08:29
  • @PathikVejani You should be able to do this with template driven forms as well, but the code wouldn't be as clean. You should be able to prevent going onto the next steps by using the [completed] and [editable] directives by adding them to the corresponding mat-step elements. – saglamcem Dec 09 '19 at 08:33
  • @saglamcem any example would be appreciated. – Pathik Vejani Dec 09 '19 at 08:34
  • @PathikVejani can i know any specific reason for not using formGroup, Drawbacks or disadvantages of formGroup – mayur Dec 09 '19 at 08:38
  • @PathikVejani I'll try to provide a stackblitz in a couple of hours - but the essence would be that you keep an object in the ts file like user: {fname: string, lname: string}, bind those values to the template using [(ngModel)] (like [(ngModel)]="user.fname"), and when checkData() is called, just check the user object with your necessary validations :) – saglamcem Dec 09 '19 at 08:38
  • @mayur I am loading components dynamic in stepper and I don't know how to handle those in click of save button. Also, there are drop-down, checkboxex etc.. – Pathik Vejani Dec 09 '19 at 08:44
  • 1
    Reactive approach has much more options and can handle dynamic data and dynamic form elements in a breeze, but it needs some minor preparation to setup, but in the end you can do much more with Reactive forms, but if you just use a smaller setup then I recomment using the template driven approach like I posted below. – Ling Vu Dec 09 '19 at 08:53

1 Answers1

2

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

Ling Vu
  • 4,740
  • 5
  • 24
  • 45