I've created my own scss theme and declared it in angular-cli.json, all works fine.
Now I need to dynamically change the theme.
I've tried to add the second theme in angular-cli.json, but as expected it overrides the first one.
So maybe one option would be to remove the theme declaration from angular-cli.json and have 2 components, each with it's own scss style, one overriding the other, the only difference between them being the styleUrls.
Or is there other recommended way to load dynamically a scss?
As of Angular 5.1, this is how I achieved dynamic theme changes.
*Edit: This still works as of Angular 7+
Working editable example - https://stackblitz.com/edit/dynamic-material-theming
In my theme.scss file, I include a default theme(notice it isn't kept under a class name - this is so Angular will use it as the default), and then a light and dark theme.
theme.scss
@import '~@angular/material/theming'; @include mat-core(); // Typography $custom-typography: mat-typography-config( $font-family: Raleway, $headline: mat-typography-level(24px, 48px, 400), $body-1: mat-typography-level(16px, 24px, 400) ); @include angular-material-typography($custom-typography); // Default colors $my-app-primary: mat-palette($mat-teal, 700, 100, 800); $my-app-accent: mat-palette($mat-teal, 700, 100, 800); $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent); @include angular-material-theme($my-app-theme); // Dark theme $dark-primary: mat-palette($mat-blue-grey); $dark-accent: mat-palette($mat-amber, A200, A100, A400); $dark-warn: mat-palette($mat-deep-orange); $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn); .dark-theme { @include angular-material-theme($dark-theme); } // Light theme $light-primary: mat-palette($mat-grey, 200, 500, 300); $light-accent: mat-palette($mat-brown, 200); $light-warn: mat-palette($mat-deep-orange, 200); $light-theme: mat-light-theme($light-primary, $light-accent, $light-warn); .light-theme { @include angular-material-theme($light-theme) }
In the app.component file, I include OverlayContainer from @angular/cdk/overlay. You can find Angular's documentation for this here https://material.angular.io/guide/theming; though their implementation is a little different. Please note, I also had to include OverlayModule as an import in app.module as well.
In my app.component file, I also declared @HostBinding('class') componentCssClass;
as a variable, which will be used to set the theme as a class.
app.component.ts
import {Component, HostBinding, OnInit} from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Version } from './classes/version'; import { OverlayContainer} from '@angular/cdk/overlay'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { constructor(private http: HttpClient, public overlayContainer: OverlayContainer) {} title = 'app'; version: Version; @HostBinding('class') componentCssClass; ngOnInit() { this.getVersion(); } onSetTheme(theme) { this.overlayContainer.getContainerElement().classList.add(theme); this.componentCssClass = theme; } getVersion() { this.http.get<Version>('/api/version') .subscribe(data => { this.version = data; }); } }
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; import { AppComponent } from './app.component'; import { OverlayModule} from '@angular/cdk/overlay'; @NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, HttpClientModule, BrowserAnimationsModule, MatCardModule, MatButtonModule, OverlayModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
Finally, call the onSetTheme function from your view.
app.component.html
<button mat-raised-button color="primary" (click)="onSetTheme('default-theme')">Default</button> <button mat-raised-button color="primary" (click)="onSetTheme('dark-theme')">Dark</button> <button mat-raised-button color="primary" (click)="onSetTheme('light-theme')">Light</button>
You might consider using an observable so that the functionality would be more dynamic.
I found my answer in Change Material design theme for Angular 2. There is a good GIT example at https://github.com/jelbourn/material2-app.
So I use the same single scss theme file, but I added to it a new class for the new theme:
.m2app-dark { $dark-primary: md-palette($md-pink, 700, 500, 900); $dark-accent: md-palette($md-blue-grey, A200, A100, A400); $dark-warn: md-palette($md-deep-orange); $dark-theme: md-dark-theme($dark-primary, $dark-accent, $dark-warn); @include angular-material-theme($dark-theme); }
This one is used in the html, and is active or not depending on the value of a boolean:
<md-sidenav-layout [class.m2app-dark]="isDarkTheme">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With