1

For a project I have used the mat-slide-toggle of the Materials library. Now I want to change the color of the slider and the circle, which are the classes mat-slide-toggle-bar and mat-slide-toggle-thumb. I can set the background-color of both via the css-file, but here's the catch. I have several slide-toggles which all need different colors. The colors are defined in a dataset available in the component. I can access this dataset in the html, but not in the css. I can't use style="background-color: ..." on the mat-slide-toggle because it is not on the right class. The two classes I need are not directly visible in the html.

Html looks like this:

<span *ngFor="let data of dataSets">
<mat-slide-toggle (change)="toggleDataSet($event)">{{data.label}}</mat-slide-toggle>
</span>

So I need to either access the dataset in the css or somehow be able to set the background-color on nested classes not visible in the html. Is there a way to do this?

Century
  • 283
  • 1
  • 4
  • 22

1 Answers1

5

For changing the color of the sliders dynamically, you can create a Directive that receives the color for the circle and the one for the slider as inputs. The directive add attributes on the element and adds the styling needed to change the colors:

There is a similar answer given for changing the color for a progress bar here: Change angular material progress bar color from code.

The directive you need looks like this:

@Directive({
  selector: '[sliderColor]'
})
export class SliderColorDirective implements OnChanges {
  static sliderNumberCounter = 0;

  @Input() circleColor: number;
  @Input() sliderColor: number;
  styleElement: HTMLStyleElement = document.createElement('style');

  attributeName: string;

  constructor(private el: ElementRef) {
    this.attributeName = `slider-color-${SliderColorDirective.sliderNumberCounter}`;
    SliderColorDirective.sliderNumberCounter++;
    const nativeEl: HTMLElement = this.el.nativeElement;
    nativeEl.setAttribute(this.attributeName, '');
    nativeEl.appendChild(this.styleElement);
  }

  ngOnChanges(): void {
    this.setColors();
  }

  setColors(): void {
    this.styleElement.innerText = `
      [${this.attributeName}] .mat-slide-toggle-bar {
        background-color: ${this.sliderColor};
      }
      [${this.attributeName}] .mat-slide-toggle-thumb {
        background-color: ${this.circleColor};
      }
    `;
  }
}

The directive can be used like this:

<mat-slide-toggle sliderColor [sliderColor]="'red'" [circleColor]="'black'">{{data.label}}</mat-slide-toggle>
Darius Bogdan
  • 897
  • 1
  • 9
  • 19
  • Awesome! I will try it out as soon as I'm able and let you know if it works and then accept your answer. – Century Mar 21 '20 at 15:21
  • I was able to implement it and it worked perfectly. The only change I would suggest is to add `.mat-checked` directly following the `attributeName`. If you don't, you get the default colours on the checked-version and your own colours on the unchecked one, while I wanted the checked-version to have my colours and I'm fine with the default grey for unchecked. – Century Mar 23 '20 at 22:22
  • To make this work on IE, you should avoid the line breaks. – Century Mar 30 '20 at 16:56
  • This doesn't seem to work for me.. I always get Can't bind to 'sliderColor' since it isn't a known property of 'mat-slide-toggle'. Any idea why? – thomas Sep 27 '20 at 11:19
  • @thomas Did you add the directive to the declarations in the module you want to use it? Or if it is used in multiple modules from the application, you should create a shared module and declare and export the directive from there and add the shared module to the imports from you module – Darius Bogdan Sep 28 '20 at 06:38