Search code examples
cssangulartypescriptangular-materialangular-material-stepper

Angular Material: How to set each mat-horizontal-stepper stepper icon with different background color in TS


I'm unable to set the icon colors

I have a mat-horizontal-stepper with five mat-steps (e.g. named Part A, Part B ... Part E). Each part (mat-step) may have different colors depending some business rules.

I know how to change the "selected" mat-step or how to change the color for ALL the mat-steps (with the same color) but can't figure out how to change it dynamically so each Part may have different icon background colors.

Using Angular v7

The following is a style to set the third mat-step icon green. Id does work but I don't how to change the color dynamically at run-time from the component (typescript).

::ng-deep .mat-step-header:nth-of-type(3) .mat-step-icon         {
    background-color: green!important; 
 } 

Also I tried using [ngClass] but it is ignored when used as a mat-step attribute. It only works if I enclose the step label within and use it there but that is not the requirement (I need to change the background color of the icon... not the labels).

Expected result: Able to set each each step with different columns depending the level of completion for each step. (mat-steps could be a combination of yellow, red, green and black),

Actual result: Unable to change icon colors based on component variable settings


Solution

  • The question is really about controlling CSS variables via TS - i got help from this post here;

    • CSS: we assign the 3 variables to the 3 icons which we needed to color
    • HTML: We created 2 divs firstClass & secondClass in addition to the <body>, to which we can assign the uniquely named variables color1, color2 and color3;
    • Since we are using 'mat-table' we can't use [ngStyle] or [ngClass] because the material elements are created at run time and we can only operate on any of them AfterViewInit event, so it is here that we assign values to our 2 divs & <body> tag;

    relevant CSS:

    ::ng-deep .mat-step-header:nth-of-type(1) .mat-step-icon {
        background-color: var(--my-var1);
     } 
    
    ::ng-deep .mat-step-header:nth-of-type(2) .mat-step-icon {
        background-color: var(--my-var2);
     } 
    
    ::ng-deep .mat-step-header:nth-of-type(3) .mat-step-icon {
        background-color: var(--my-var3);
     } 
    

    relevant HTML:

    <div class='firstClass'>
        <div class=' secondClass'>
            <mat-horizontal-stepper labelPosition="bottom" #stepper>
                <mat-step [stepControl]="firstFormGroup">
                    <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" optional>
            <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>
      </mat-horizontal-stepper>
      <div>
    <div>
    

    relevant TS:

    import {Component, OnInit,AfterViewInit } from '@angular/core';
    import {FormBuilder, FormGroup, Validators} from '@angular/forms';
    
    @Component({
      selector: 'stepper-label-position-bottom-example',
      templateUrl: 'stepper-label-position-bottom-example.html',
      styleUrls: ['stepper-label-position-bottom-example.css'],
    })
    export class StepperLabelPositionBottomExample implements OnInit, AfterViewInit {
      firstFormGroup: FormGroup;
      secondFormGroup: FormGroup;
      color1:string = 'green';
      color2:string = 'yellow';
      color3:string = 'red';
    
      constructor(private _formBuilder: FormBuilder) {}
    
      ngOnInit() {
        this.firstFormGroup = this._formBuilder.group({
          firstCtrl: ['', Validators.required]
        });
        this.secondFormGroup = this._formBuilder.group({
          secondCtrl: ['', Validators.required]
        });
      }
    
      ngAfterViewInit(){
        document.querySelector("body").style.cssText = "--my-var1: "+this.color1;
        (<HTMLElement>document.querySelector('.secondClass')).style.cssText = "--my-var2: "+this.color2;
        (<HTMLElement>document.querySelector('.firstClass')).style.cssText = "--my-var3: "+this.color3;
      }
    
    }
    

    complete working stacblitz here