如何在服务上使用 SnackBar 以在 Angular 2 中的每个组件中使用

Posted

技术标签:

【中文标题】如何在服务上使用 SnackBar 以在 Angular 2 中的每个组件中使用【英文标题】:How to use SnackBar on service to use in every component in Angular 2 【发布时间】:2017-08-03 07:35:07 【问题描述】:

我有一个可以工作的小吃店,但它只在每个组件上,我想将它添加到我的服务中,所以我将调用它。这是我在component.ts 上的示例

import  MdSnackBar, MdSnackBarRef  from '@angular/material';
...
export class EmployeeListComponent implements OnInit 
  public toastRef: MdSnackBarRef<any>;
  constructor(private _activatedRoute:ActivatedRoute,private router: Router, private http:PMISHttpService, private toast: MdSnackBar) 

  ngOnInit() 
    this.notify('test');
  
  ...
  notify (text: string) 
    this.toastRef = this.toast.open(text, null);
    setTimeout(() => 
      this.toastRef.dismiss();
    , 5000);
  
  ...

【问题讨论】:

【参考方案1】:

如果您希望 SnackBar 在您的整个应用程序中工作,您应该将其放入您的 app.component 并通过服务与其通信。

notification.service.ts:

public notification$: Subject<string> = new Subject();

app.component.ts:

constructor(
  private notificationService: NotificationService, private snackBar: MatSnackBar
) 
  this.notificationService.notification$.subscribe(message => 
    this.snackBar.open(message);
  );

任何.component.ts:

this.notificationService.notification$.next('this is a notification');

【讨论】:

通知功能放在哪里?对不起,我是新手 你创建了一个全局服务,它有一个 'subj_notification' rxjs 主题,你的 app.component 有snackBar 并且订阅了'subj_notification'。此时,您应用中的任何组件都可以调用服务的 subj_notification.next() 并且您的应用组件将收到主题更改的通知。【参考方案2】:

要让它无处不在,请为它创建一个服务。你也应该使用snackbar config来设置持续时间并将snackbar公开:

import Injectable, NgZone from '@angular/core';
import MatSnackBar from '@angular/material';

@Injectable()
export class CustomSnackbarService 

    constructor(
      public snackBar: MatSnackBar,
      private zone: NgZone
    ) 

    public open(message, action = 'success', duration = 50000) 
        this.zone.run(() => 
            this.snackBar.open(message, action,  duration );
        );
    

还需要在ngZone:https://github.com/angular/material2/issues/9875中运行

然后在组件中:

customSnackbarService.open('hello')

【讨论】:

这对我很有用!我只是做了一个小修改,让调用者可以访问 SnackBarRef: return this.zone.run(() => return this.snackBar.open(message, action, duration ); );跨度> 有意思,zone.run 是否返回内部函数? 不确定是否仍需要 NgZone。我试过没有,代码似乎仍然可以工作(使用 Angular 10)。无论如何,感谢您的解决方案! 很有可能【参考方案3】:

您可以轻松做到这一点。请在下面找到我在我的一个项目中使用的示例的示例,它工作得很好

import  Injectable  from '@angular/core';
import 
  MatSnackBar,
  MatSnackBarConfig,
  MatSnackBarHorizontalPosition,
  MatSnackBarVerticalPosition,
  MatSnackBarRef
 from '@angular/material';

@Injectable()
export class SnackBarService 

  snackBarConfig: MatSnackBarConfig;
  snackBarRef: MatSnackBarRef<any>;
  horizontalPosition: MatSnackBarHorizontalPosition = 'center';
  verticalPosition: MatSnackBarVerticalPosition = 'top';
  snackBarAutoHide = '1500';

  constructor(private snackBar: MatSnackBar)  

  openSnackBar(message) 
    this.snackBarConfig = new MatSnackBarConfig();
    this.snackBarConfig.horizontalPosition = this.horizontalPosition;
    this.snackBarConfig.verticalPosition = this.verticalPosition;
    this.snackBarConfig.duration = parseInt(this.snackBarAutoHide, 0);
    this.snackBarConfig.panelClass = 'custom-snackbar';
    this.snackBarRef = this.snackBar.open(message, '', this.snackBarConfig);



现在,你只需要在你的组件或者你想使用它的地方注入这个服务,然后调用 openSnackBar() 方法来显示你想要显示的消息。

希望这会有所帮助!

【讨论】:

简单明了的答案【参考方案4】:

这是我的工作示例(Angular 11,Angular Material 11.0.1)。

最重要的部分是在 app.module.ts 中包含 MatSnackBarModule。另外,不要忘记导入 BrowserAnimationsModule

import  MatSnackBarModule  from '@angular/material/snack-bar';
import  BrowserAnimationsModule  from '@angular/platform-browser/animations';

@NgModule(
  imports: [
    MatSnackBarModule,
    BrowserAnimationsModule
    ...
  ],

那么,我的服务是这样的

import  Injectable  from '@angular/core';
import  MatSnackBar  from '@angular/material/snack-bar';

@Injectable(
  providedIn: 'root'
)
export class SnackbarService 

  constructor(
    private _snackBar: MatSnackBar) 
  

  error(message: string) 
    return this._snackBar.open(message, undefined, panelClass: ['snackbar-error']);
  

  success(message: string) 
    return this._snackBar.open(message, undefined, panelClass: ['snackbar-success']);
  

  info(message: string) 
    return this._snackBar.open(message, undefined, panelClass: ['snackbar-info']);
  


为了定义样式,我将这些添加到 styles.scss

.mat-simple-snackbar 
  font-size: 1.2em;
  color: white;


.snackbar-error 
  background-color: red;


.snackbar-success 
  background-color: green;


.snackbar-info 
  background-color: blue;


这样,我现在可以从代码中的任何位置(包括来自其他模块的组件)调用 SnackBar。使用示例:

import  Component  from '@angular/core';
import  AuthService  from 'src/app/services/auth/auth.service';
import  SnackbarService  from 'src/app/services/snackbar.service';

@Component(
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
)
export class LoginComponent 

  loginForm: any;

  constructor(private authService: AuthService, private snackbar: SnackbarService)  

  onSubmit() 
      this.authService.login(this.loginForm).subscribe(res => 
        this.snackbar.success('Logged in');
      , e => 
        this.snackbar.error('Login failed');
      );
  



【讨论】:

与 Angular 10 和 Angular Material 完美配合 ^10.2.7 您可以升级具有额外属性的小吃栏,例如 5 秒后消失,或者将酒吧从下到上重新定位,如下所示:error(message: string) return this._snackBar.open(message, null, duration: 5000, verticalPosition: 'top', horizontalPosition: 'center', panelClass: ['snackbar-error'] ); 很好的答案,你应该使用undefined 而不是null @andrèscoronado 为什么是undefined @TomasLukac typescript (method) MatSnackBar.open(message: string, action?: string | undefined, config?: MatSnackBarConfig&lt;any&gt; | undefined): MatSnackBarRef&lt;TextOnlySnackBar&gt; @TomasLukac 的非常好的和简单的回答我添加了额外的参数来自动关闭小吃店 panelClass: ['snackbar-info'], duration: 5000 【参考方案5】:

我正在使用版本 version": "2.0.0-beta.10", 这就是我为使其正常工作所做的工作

在 ApModule 中

import  NotificationService  from "./notification/notification.service";
import  MdSnackBarModule  from "@angular/material";

@NgModule(
  imports: [
    MdSnackBarModule,
    FormsModule
  ],
  providers: [WebService, NotificationService]

按照上一篇文章的建议创建通知服务

import  Injectable  from "@angular/core";
import 
  MdSnackBar,
  MdSnackBarConfig,
  // MdSnackBarHorizontalPosition,
  // MdSnackBarVerticalPosition,
  MdSnackBarRef
 from "@angular/material";

@Injectable()
export class NotificationService 
  private snackBarConfig: MdSnackBarConfig;
  private snackBarRef: MdSnackBarRef<any>;
    private snackBarAutoHide = "5000"; //milliseconds for notification , 5 secs

  constructor(private sb: MdSnackBar) 

  openSnackBar(message) 
    this.snackBarConfig = new MdSnackBarConfig();
    //this.snackBarConfig.horizontalPosition = this.horizontalPosition; only in current version Demo uses very old version . need to upgrade later
    //this.snackBarConfig.verticalPosition = this.verticalPosition; only in current version Demo uses very old version . need to upgrade later
    this.snackBarConfig.duration = parseInt(this.snackBarAutoHide, 0);
      this.sb.open(message, "", this.snackBarConfig);
  

如下图消费服务

   this.notify.openSnackBar(message);

【讨论】:

以上是关于如何在服务上使用 SnackBar 以在 Angular 2 中的每个组件中使用的主要内容,如果未能解决你的问题,请参考以下文章

如何固定 Snackbar 的高度和位置?

Flutter - 如何在“Future”中显示“snackbar”

如何在关闭屏幕时关闭打开的 SnackBar?

如何转换 PFX 证书文件以在 linux 服务器上与 Apache 一起使用?

如何在对话框覆盖的底部添加 SnackBar

selenium 运行测试时如何显示 Snackbar?