Tuesday, June 2, 2020

Angular Material Design Stepper icon and behavior

Angular material design stepper can be used to create wizard style UI to lead users to finish a task step by step. The behavior of the stepper is decided by the properties of stepper.

1. linear property on stepper 
If linear proper is set to false, then user can move to the next step by clicking the next button or by clicking on any step icon,  no matter the current step is completed or not.
If linear property is set to true, then the completed attribute on the current step must be set to true in order to move to the next step immediately following the current step, user cannot select any arbitrary step by clicking the step icon.
Linear property does not affect the step icon.

2. Completed property on each step
The completed property for each step indicates whether the input in the current step has passed the validation. 
Completed property works with the stepper's linear property mentioned above, if linear property is set to true, then the Completed property must be set to true for for user to move to the next step by clicking the next button.

3. Editable property on each step
The editable property for each step indicates whether user can move back to a step by clicking the previous button or by clicking the step icon.
If the editable property is set to false, then once user move to the next step, they will not be able to move back to this step again. In this case, the next step should not show the previous button to let user moves back.

The step icon is also controlled by the status of each step. By default, all step icons are shown as circled number as below if editable is set to true and completed set to false. The current step is indicated by blue background.

If a step's completed property is set to true, and it is not the current active step, and the step is not the current selected step, then the step icon will show the create icon (pen icon) to indicate this step has been finished and in good state as below
If a step's competed property is set to true and the step's editable property is also set to true, and the setp is not the current selected step, then the step icon will show the done icon (check mark ion) to indicate the step is finished and in good state and user cannot move back to edit or view it.


Developers can also customize the step icon using ngTemplate. The same icon customization will apply to all the steps.
There are three icons that can be customized, the matStepperIcon attribute value is used to indicate which icon should be used for which state:
matStepperIcon="number" - For the regular number icon 
matStepperIcon="edit" - For step of editable and completed
matStepperIcon="done" - For step of not editable and completed


The below code customizes the edit icon to alarm, the done icon to book, and the regular number icon to face. 

<mat-horizontal-stepper [linear]="isLinear" #stepper>
  <ng-template matStepperIcon="edit">
    <mat-icon>alarm</mat-icon>
  </ng-template>

  <ng-template matStepperIcon="done">
    <mat-icon>book</mat-icon>
  </ng-template>

  <!-- Custom icon with a context variable. -->
  <ng-template matStepperIcon="number" >
    <mat-icon>face</mat-icon>
  </ng-template>

The result looks like below


Developer can also customize the number only for the number icon as below
<ng-template matStepperIcon="number" let-index="index">
    {{index + 10}}
  </ng-template>


The related code used in the testing is shown below
Component html file:
<div>
  <button mat-raised-button (click)="isLinear = !isLinear" id="toggle-linear">
    stepper Linear: {{isLinear ? 'Enabled' : 'Disabled'}}
  </button>
</div>
<div>
  <button mat-raised-button (click)="isStep1Editable = !isStep1Editable">
    step 1 editable: {{isStep1Editable ? 'Editable' : 'Not Editable'}}
  </button>
  <button mat-raised-button (click)="isStep1Completed = !isStep1Completed">
    step 1 complete: {{isStep1Completed ? 'Completed' : 'Not Completed'}}
  </button>
</div>
<div>
  <button mat-raised-button (click)="isStep2Editable = !isStep2Editable">
    step 2 editable: {{isStep2Editable ? 'Editable' : 'Not Editable'}}
  </button>
  <button mat-raised-button (click)="isStep2Completed = !isStep2Completed">
    step 2 complete: {{isStep2Completed ? 'Completed' : 'Not Completed'}}
  </button>
</div>
<div>
  <button mat-raised-button (click)="isStep3Editable = !isStep3Editable">
    step 3 editable: {{isStep3Editable ? 'Editable' : 'Not Editable'}}
  </button>
  <button mat-raised-button (click)="isStep3Completed = !isStep3Completed">
    step 3 complete: {{isStep3Completed ? 'Completed' : 'Not Completed'}}
  </button>
</div>
<mat-horizontal-stepper [linear]="isLinear" #stepper>
  <mat-step [editable]="isStep1Editable" [completed]="isStep1Completed">
    <ng-template matStepLabel>Business information</ng-template>
    <mat-form-field>
      <mat-label>Name</mat-label>
      <input matInput placeholder="Last name, First name" [formControl]="firstInput" required>
    </mat-form-field>
    <div>
      <button mat-button matStepperNext>Next</button>
    </div>
  </mat-step>
  <mat-step [editable]="isStep2Editable" [completed]="isStep2Completed">
    <ng-template matStepLabel>Fill out your address</ng-template>
    <mat-form-field>
      <mat-label>Address</mat-label>
      <input matInput [formControl]="secondInput" placeholder="Ex. 1 Main St, New York, NY" required>
    </mat-form-field>
    <div>
      <button mat-button matStepperPrevious>Back</button>
      <button mat-button matStepperNext>Next</button>
    </div>
  </mat-step>
  <mat-step [editable]="isStep3Editable" [completed]="isStep3Completed">
    <ng-template matStepLabel>Done</ng-template>
    <p>You are now done.</p>
    <div>
      <button mat-button matStepperPrevious>Back</button>
      <button mat-button (click)="stepper.reset()">Reset</button>
    </div>
  </mat-step>
</mat-horizontal-stepper>
Component ts file
export class AppComponent implements OnInit {
  title = 'steppersample';
  isLinear = false;
  isStep1Editable = true;
  isStep1Completed = false;
  isStep2Editable = true;
  isStep2Completed = false;
  isStep3Editable = true;
  isStep3Completed = false;
  firstInput: FormControl;
  secondInput: FormControl;
  ngOnInit(){
    this.firstInput = new FormControl('');
    this.secondInput = new FormControl('');
  }
}

No comments:

Post a Comment