4

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.

nash11
  • 8,220
  • 3
  • 19
  • 55
Andrew Medhurst
  • 103
  • 1
  • 2
  • 6
  • I have tried to set completed property true. It's working in this example:https://stackblitz.com/edit/angular-fnqj4t – Chellappan வ Sep 18 '19 at 18:42
  • Hi Andrew, welcome to stackoverflow. Can you share the typescript code of your component and it's markup please. – user1859022 Sep 18 '19 at 20:27
  • @user1859022 - Thanks for the response. If you take a look at the answer that I marked as correct, my code looks very similar to what is listed there. – Andrew Medhurst Sep 19 '19 at 17:51

2 Answers2

4

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.

nash11
  • 8,220
  • 3
  • 19
  • 55
  • Thanks for the thoughtful response. This worked well for me. As an aside curiousity, why can't I simply access isCurrentStep and set it to false like this: ```this.stepper.selected.isCurrentStep = false;```, but I can access ```this.stepper.selected.completed = true;```? For clarification, 'this.stepper' is the name of my MatHorizontalStepper within my .ts file. – Andrew Medhurst Sep 19 '19 at 17:47
  • 1
    You can see the [API](https://material.angular.io/components/stepper/api) page in the docs to see what all is exposed by `mat-stepper`. If you check the Github link in my answer and go to the `_getGuidelineLogic` function (which is where the above `if` condition in my answer is placed), you can see that `isCurrentStep` is a local variable which receives its value from `_isCurrentStep` which is a private function, so it cannot be accessed using `ViewChild`. – nash11 Sep 19 '19 at 17:59
0

Observing the code https://stackblitz.com/edit/angular-mat-stepper-complete I realized that to work without hack.

I needed to configure custom icons settings and more as follows:

 @Component({
  selector: 'hello-form',
  templateUrl: './hello-form.component.html',
  styleUrls: ['./hello-form.component.scss'],
  providers: [
    {
      provide: STEPPER_GLOBAL_OPTIONS,
      useValue: { displayDefaultIndicatorType: false }
    }
  ]
})
export class HelloFormComponent implements OnInit {
...

Providers can also be configured in app.module.ts

<mat-step
  state="CONFIRMED"
  [completed]="true"
>

The completed attribute works with databind

...
  </mat-step>   
  <ng-template matStepperIcon="CONFIRMED">
    <mat-icon>bookmark_added</mat-icon>
  </ng-template>
...
</mat-stepper>

Need to set custom icons for each status

Wendel
  • 2,809
  • 29
  • 28