web-dev-qa-db-fra.com

Matières dynamiques angulaires à 2 matériaux

J'ai créé mon propre thème scss et l'ai déclaré dans angular-cli.json, tout fonctionne bien.

Maintenant, je dois changer le thème de manière dynamique. 

J'ai essayé d'ajouter le deuxième thème dans angular-cli.json, mais comme prévu, il remplace le premier. 

Donc, une option serait peut-être de supprimer la déclaration de thème d'angular-cli.json et d'avoir 2 composants, chacun avec son propre style scss, l'un écrasant l'autre, la seule différence entre eux étant styleUrls.

Ou existe-t-il un autre moyen recommandé de charger dynamiquement un fichier scss? 

13
Monica L

Depuis Angular 5.1, c’est ainsi que j’ai réalisé les changements de thème dynamiques.

* Edit: Cela fonctionne toujours à partir de Angular 7+

Exemple éditable de travail - https://stackblitz.com/edit/dynamic-material-theming

Dans mon fichier theme.scss, j'inclus un thème par défaut (notez qu'il n'est pas conservé sous un nom de classe; Angular l'utilisera par défaut), puis un thème clair et sombre.

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)
}

Dans le fichier app.component, j'inclus OverlayContainer à partir de @ angular/cdk/overlay. Vous pouvez trouver la documentation de Angular à ce sujet ici https://material.angular.io/guide/theming ; bien que leur mise en œuvre soit un peu différente. Veuillez noter que je devais également inclure OverlayModule en tant qu'import dans app.module.

Dans mon fichier app.component, j'ai également déclaré @HostBinding('class') componentCssClass; en tant que variable, qui sera utilisée pour définir le thème en tant que classe.

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 {}

Enfin, appelez la fonction onSetTheme à partir de votre vue.

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>

Vous pouvez envisager d'utiliser un observable afin que la fonctionnalité soit plus dynamique.

21
K. Waite

J'ai trouvé ma réponse dans Changer le thème de conception de matériau pour Angular 2 . Il existe un bon exemple GIT sur https://github.com/jelbourn/material2-app .

J'utilise donc le même fichier de thème scss, mais j'y ai ajouté une nouvelle classe pour le nouveau thème:

.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);
}

Celui-ci est utilisé dans le HTML, et est actif ou non en fonction de la valeur d'un booléen:

 <md-sidenav-layout [class.m2app-dark]="isDarkTheme">
5
Monica L

Vous pouvez basculer entre les thèmes en ajoutant ou en supprimant la classe css (y compris le thème matériel) sur la balise body au moment de l’exécution, en fonction du thème actuel.

par exemple étape 1.

ajoutez l'identifiant à la balise body dans le fichier html afin que vous puissiez classer élément par élément.

<body id="themeTag">
<app-root></app-root>
</body>

étape 2.

créez un deuxième thème dans votre fichier scss, fichier qui est inclus dans angular.json dans angular 6 et .angular-cli.json dans une version angulaire inférieure à 6.

@include mat-core();
$primary: mat-palette($mat-blue);
$accent: mat-palette($mat-yellow);
$warn: mat-palette($mat-red);

$light-theme: mat-light-theme($primary, $accent, $warn);

@include angular-material-theme($light-theme);

$dark-theme: mat-dark-theme($primary, $accent, $warn);

.dark-theme { // css class for dark theme
  @include angular-material-theme($dark-theme);
}

étape 3.

cliquez sur le bouton pour changer la classe de la balise body.

toggleTheme(){
   this.isDarkTheme = !this.isDarkTheme;
   if(this.isDarkTheme){
     /* here themeTag is id of body tag and dark-theme is css class created in theme file */
     document.getElementById('themeTag').classList.add('dark-theme');
   }else{
     document.getElementById('themeTag').classList.remove('dark-theme');
   }
}
1
Ravi Sevta