I am trying to use an ng-template
with the matStepperIcon
property to override the default Angular Material's matStepper's icons. I also want to pass some data, and I tried using ng-container
and *ngTemplateOutlet
, however it only partially works.
As you can see from the following code, I would expect the print
function to always print a defined value, however, after correctly printing the seven IDs of the steps it prints undefined
seven times. Why is that and how do I prevent that from happening?
<mat-horizontal-stepper labelPosition="bottom">
<ng-container *ngFor="let step of form.steps">
<ng-template #ref let-step="id" matStepperIcon="edit">
<mat-icon>clear</mat-icon>
{{ print(step) }}
</ng-template>
<ng-template #ref let-step="id" matStepperIcon="number">
<mat-icon>clear</mat-icon>
{{ print(step) }}
</ng-template>
<ng-template #ref let-step="id" matStepperIcon="done">
<mat-icon>clear</mat-icon>
{{ print(step) }}
</ng-template>
<ng-container *ngTemplateOutlet="ref; context: step"></ng-container>
<mat-step>
<ng-template matStepLabel>
{{ step.id }}:
{{ translateService.currentLang === "it" ? step.name : step.nameEn }}
</ng-template>
<!-- Step content-->
</mat-step>
</ng-container>
</mat-horizontal-stepper>
Changing my code to the following, on the other hand, causes the print
function to print all the correct IDs but it also prints the ID of the last step 8 times.
<mat-horizontal-stepper labelPosition="bottom">
<ng-container *ngFor="let step of form.steps">
<ng-template #ref matStepperIcon="edit">
{{ print(step.id) }}
<mat-icon>clear</mat-icon>
</ng-template>
<ng-template #ref matStepperIcon="number">
{{ print(step.id) }}
<mat-icon>clear</mat-icon>
</ng-template>
<ng-template #ref matStepperIcon="done">
{{ print(step.id) }}
<mat-icon>clear</mat-icon>
</ng-template>
<ng-container *ngTemplateOutlet="ref; context: step"></ng-container>
<mat-step>
<ng-template matStepLabel>
{{ step.id }}:
{{ translateService.currentLang === "it" ? step.name : step.nameEn }}
</ng-template>
<!-- Step content-->
</mat-step>
</ng-container>
</mat-horizontal-stepper>
If you want to use custom icons with MatStepper you should do several things:
We could disable displayDefaultIndicatorType
like
providers: [{
provide: STEPPER_GLOBAL_OPTIONS, useValue: {displayDefaultIndicatorType: false}
}]
But it won't help since Angular Material has predefined logic to show specific icon depending on internal step state https://github.com/angular/components/blob/28c36f8a02f72e51a4d6c6a797e2f913e5dede9b/src/cdk/stepper/stepper.ts#L442-L465
So, you can override base logic like here https://github.com/angular/components/issues/18307
@ViewChild(MatHorizontalStepper, { static: true }) stepper: MatHorizontalStepper;
ngOnInit() {
this.stepper._getIndicatorType = (i, state) => state || 'number';
}
Decide which icon to show depending on step
<mat-step [state]="step.state">
steps: [
{
id: 218,
name: 'Dati richiedente',
nameEn: 'Applicant data',
state: 'home',
},
{
id: 219,
name: 'Richiesta Meeting',
nameEn: 'Meeting request',
state: 'edit'
},
Use built-in matStepperIcon
context to access rendering index
. With this index you can access corresponding step
:
<ng-template let-i="index" matStepperIcon="home">
<mat-icon>home</mat-icon>
{{ print(form.steps[i]) }}
</ng-template>