【问题标题】:Angular material Snackbar configuration with custom panelClass configuration for error, success, warning messagesAngular 材质 Snackbar 配置与自定义 panelClass 配置,用于错误、成功、警告消息
【发布时间】:2020-09-10 03:06:35
【问题描述】:

我在我的 Angular 应用程序中创建了一个全局的snackBarService。我想根据消息类型(错误、成功、警告等)自定义panelClass。我采用的方法是在构造函数中进行全局配置,这有助于为小吃店定义全局样式/配置,并将添加自定义类以根据消息类型更改背景颜色。

SnackBarService.ts

import { Injectable, NgZone } from "@angular/core";
import { MatSnackBar, MatSnackBarConfig } from "@angular/material";

@Injectable({
  providedIn: "root",
})
export class SnackbarService {
  private config: MatSnackBarConfig;

  constructor(private snackbar: MatSnackBar, private zone: NgZone) {
    this.config = new MatSnackBarConfig();
    this.config.panelClass = ["snackbar-container"];
    this.config.verticalPosition = "top";
    this.config.horizontalPosition = "right";
    this.config.duration = 4000;
  }

  error(message: string) {
    this.config.panelClass = ["snackbar-container", "error"];
    this.show(message);
  }

  success(message: string) {
    this.config.panelClass = ["snackbar-container", "success"];
    this.show(message);
  }

  warning(message: string) {
    this.config.panelClass = ["snackbar-container", "warning"];
    this.show(message);
  }

  private show(message: string, config?: MatSnackBarConfig) {
    config = config || this.config;
    this.zone.run(() => {
      this.snackbar.open(message, "x", config);
    });
  }
}

app.scss

.snackbar-container {
  margin-top: 70px !important;
  color: beige;
  &.error {
    background-color: #c62828 !important;
  }
  &.success {
    background-color: #2e7d32 !important;
  }

  &.warning {
    background-color: #ff8f00 !important;
  }
}

从组件中我将使用这样的服务

this.snackbarService.success("This message is from snackbar!!!");

以上代码完美运行。

但是,

由于panelClass没有.push方法,我无法添加动态类,因此我每次都需要像this.config.panelClass = ["snackbar-container", "error"];这样复制全局类

 error(message: string) {
    this.config.panelClass.push("error"); // this throws error in typescript
    this.show(message);
  }

有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: javascript angular angular-material snackbar


    【解决方案1】:

    Angular Material 实际上为您提供了一种设置默认配置的本地方式,因此您无需实例化 MatSnackBarConfig 然后设置其值。在您导入 MatSnackBarModule 的模块(App/Shared/Material 模块)中,添加以下内容:

    import { MatSnackBarModule, MatSnackBarConfig, MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
    
    const matSnackbarDefaultConfig: MatSnackBarConfig = {
      verticalPosition: 'top',
      horizontalPosition: 'right',
      duration: 4000,
    };
    
    @NgModule({
      // ...
      providers: [
        {
          provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
          useValue: matSnackbarDefaultConfig,
        },
      ],
    })
    export class MaterialModule { }
    

    然后,您可以像这样使用您的服务(我添加了更多的输入内容,如果您不喜欢它并且不使用 strictNullChecks,请随时删除它们):

    import { Injectable, NgZone } from '@angular/core';
    import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
    
    // I actually recommend that you put this in a utils/helpers folder so you can use reuse it whenever needed
    export const coerceToArray = <T>(value: T | T[]): T[] => (
      Array.isArray(value)
        ? value
        : [value]
    );
    
    @Injectable({
      providedIn: 'root',
    })
    export class SnackbarService {
      constructor(private snackbar: MatSnackBar, private zone: NgZone) { }
    
      error(message: string): void {
        this.show(message, { panelClass: ['snackbar-container', 'error'] });
      }
    
      success(message: string): void {
        this.show(message, { panelClass: ['snackbar-container', 'success'] });
      }
    
      warning(message: string): void {
        this.show(message, { panelClass: ['snackbar-container', 'warning'] });
      }
    
      private show(message: string, customConfig: MatSnackBarConfig = {}): void {
        const customClasses = coerceToArray(customConfig.panelClass)
          .filter((v) => typeof v === 'string') as string[];
    
        this.zone.run(() => {
          this.snackbar.open(
            message,
            'x',
            { ...customConfig, panelClass: ['snackbar-container', ...customClasses] },
          );
        });
      }
    }
    
    

    此外,由于您的公共方法不接受其他配置来传递(例如持续时间),您可以将您的服务减少到:

    import { Injectable, NgZone } from '@angular/core';
    import { MatSnackBar } from '@angular/material/snack-bar';
    
    // Just add the new required types here and TypeScript will require the public consumer to pass a valid type
    export type SnackBarType = 'error' | 'success' | 'warning'; 
    
    @Injectable({
      providedIn: 'root',
    })
    export class SnackbarService {
      constructor(private snackbar: MatSnackBar, private zone: NgZone) { }
    
      show(message: string, type: SnackBarType): void {
        this.zone.run(() => {
          this.snackbar.open(
            message,
            'x',
            { panelClass: ['snackbar-container', type] },
          );
        });
      }
    }
    

    【讨论】:

      【解决方案2】:

      你可以这样做:

      (this.config.panelClass as string[]).push('error');
      

      但是您将添加类而不删除已经存在的类。您仍然需要每次使用初始类重置数组:

      this.config.panelClass = ['snackbar-container']
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 2016-01-25
        • 2019-04-30
        • 2021-04-27
        • 2015-06-22
        • 2023-04-09
        相关资源
        最近更新 更多