Search code examples
angularangular-materialangular-material-stepper

Angular Material Stepper Last Step accessible when everything is done without linear


Like the title says I want to make the last step just accessible when the rest is already filled.

My Steps looks like this: 1-Login Details -> 2-Personal Details -> 3-Check

It would make no sense to get to the check without having all details. But I don't want to do it linear so that you can switch between login and personal details like you want to.

HTML:

<mat-horizontal-stepper #stepper>
      <ng-template matStepperIcon="edit">
        <mat-icon>check</mat-icon>
      </ng-template>
<mat-step [stepControl]="registerForm" errorMessage="{{ 'REGISTRATION.STEPPER_ERROR_LOGIN' | translate }}"> 
...
 </mat-step>

<mat-step [stepControl]="personalForm" errorMessage="{{ 'REGISTRATION.STEPPER_ERROR_PERSONAL' | translate }}">
...
</mat-step>

<mat-step [stepControl]="registerForm && personalForm" errorMessage="Überprüfung steht aus">
...
</mat-step>
</mat-horizontal-stepper>

TS:

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

Solution

  • Solution 1:

    Add optional to the first mat-step

    <mat-step [stepControl]="registerForm" errorMessage="{{ 'REGISTRATION.STEPPER_ERROR_LOGIN' | translate }}" optional>

    Solution 2:

    1. Set mat-stepper or mat-horizontal-stepper to be linear, eg.:

      <mat-horizontal-stepper linear="true">

    2. Add completed property to the first mat-step. It allows you to go to the second step without filling the form.

      <mat-step completed>

    3. Don't use stepControl on the fist mat-step. Eg.

      <mat-step [stepControl]="firstFormGroup" completed>

    Example code:

    a) HTML:

    <mat-horizontal-stepper linear="true" #stepper>
    <mat-step completed>
      <form [formGroup]="firstFormGroup">
        <ng-template matStepLabel>Fill out your name</ng-template>
        <mat-form-field>
          <input matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
        </mat-form-field>
        <div>
          <button mat-button matStepperNext>Next</button>
        </div>
      </form>
    </mat-step>
    <mat-step [stepControl]="secondFormGroup">
      <form [formGroup]="secondFormGroup">
        <ng-template matStepLabel>Fill out your address</ng-template>
        <mat-form-field>
          <input matInput placeholder="Address" formControlName="secondCtrl" required>
        </mat-form-field>
        <div>
          <button mat-button matStepperPrevious>Back</button>
          <button mat-button matStepperNext>Next</button>
        </div>
      </form>
    </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>
    

    b) TS:

    import {Component, OnInit} from '@angular/core';
    import {FormBuilder, FormGroup, Validators} from '@angular/forms';
    
    /**
     * @title Stepper overview
     */
    @Component({
      selector: 'stepper-overview-example',
      templateUrl: 'stepper-overview-example.html',
      styleUrls: ['stepper-overview-example.css'],
    })
    export class StepperOverviewExample implements OnInit {
      isLinear = false;
      firstFormGroup: FormGroup;
      secondFormGroup: FormGroup;
    
      constructor(private _formBuilder: FormBuilder) {}
    
      ngOnInit() {
        this.firstFormGroup = this._formBuilder.group({
          firstCtrl: ['', Validators.required]
        });
        this.secondFormGroup = this._formBuilder.group({
          secondCtrl: ['', Validators.required]
        });
      }
    }