How to show that the last mat-step is complete in mat-stepper?

Andrew Medhurst picture Andrew Medhurst · Sep 18, 2019 · Viewed 9k times · Source

Okay. I can't believe that I'm posting a question for the first time over something that should be so simple to accomplish, but here we are.

I would like for the final step in my mat-horizontal-stepper to display a checkmark icon and green background once a specific button is clicked, just like the icons for the steps prior to it. That button would be the 'Yes, confirm' button in the following image.

Confirmation page

Once clicked, I would like the blue icon with the number three to change into the checkmark icon that I previously described, indicating that all steps are now completed. Steps 1 & 2 do it automatically because it seems as if the 'mat-step-icon-state-done' class gets applied to them once a button marked as 'matStepperNext' is pressed. Sadly, Step 3 does not have such a button, so it must be done manually.

Now, I've tried everything that would come up for a search regarding this. Many posts suggest using custom icons with states using <ng-template></ng-template>, but that has not worked. Others have suggested marking the step with completed=true; editable=false;, but this only works when moving to the next step as well, which means it won't apply to the final step. My hypothesis is that there must be some way to add the 'mat-step-icon-state-done' class to the mat-icon somehow, but I'm not really sure how to go about doing that. Also, please feel free to point me in the correct direction if my hunch is completely off.

Answer

nash11 picture nash11 · Sep 19, 2019

There doesn't seem to be a direct way to do this as per the docs. There is a completed and state input though which we can use on the final mat-step.

If you see the code for the stepper on GitHub, you can see the following condition

if (step._showError && step.hasError && !isCurrentStep) {
    return STEP_STATE.ERROR;
} else if (step.completed && !isCurrentStep) {
    return STEP_STATE.DONE;
} else if (step.completed && isCurrentStep) {
    return state;
}

This shows that setting completed alone is not sufficient since the final step will still be the current step. But as we can see from the condition, all we need to do now is change state as well.

In your last mat-step, add completed and state

<mat-step [completed]="completed" [state]="state">
    <ng-template matStepLabel>Done</ng-template>
        You are now done.
    <div>
        <button mat-button matStepperPrevious>Back</button>
        <button mat-button (click)="done()">Confirm</button>
    </div>
</mat-step>

Then control this in your component when the button is clicked.

completed: boolean = false;
state: string;

done() {
    this.completed = true;
    this.state = 'done';
    console.log(this.firstFormGroup.valid);
    console.log(this.secondFormGroup.valid);
}

Note: You can use the validity of the forms to conditionally set these two variables or show an error message to prompt the user to complete the rest of the steppers.

Here is a working example on StackBlitz.