简体   繁体   English

我如何使用 Angular 材料显示来自服务的 MatSnackBar?

[英]How i can display a MatSnackBar from a Service with Angular Material?

Im using: Angular V6.1.0, Angular Material V6.4.1我正在使用:Angular V6.1.0,Angular Material V6.4.1

Im trying catch the HTTP errors and show them using a MatSnackBar.我正在尝试捕获 HTTP 错误并使用 MatSnackBar 显示它们。 I seek to show this in every component of my application (where there is an http request).我试图在我的应用程序的每个组件中显示这一点(其中有一个 http 请求)。 So as not to do the repetitive code以免重复代码

Otherwise i should repeat the same code in every component for display the MatSnackBar with the errors inserted.否则我应该在每个组件中重复相同的代码以显示插入错误的 MatSnackBar。

This is my service:这是我的服务:

 import { Injectable } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http'; // import { HttpClient, HttpErrorResponse, HttpRequest } from '@angular/common/http'; import { Observable, throwError, of, interval, Subject } from 'rxjs'; import { map, catchError, retryWhen, flatMap } from 'rxjs/operators'; import { url, ErrorNotification } from '../globals'; import { MatSnackBar } from '@angular/material'; import { ErrorNotificationComponent } from '../error-notification/error-notification.component'; @Injectable({ providedIn: 'root' }) export class XhrErrorHandlerService { public subj_notification: Subject<string> = new Subject(); constructor( public snackBar: MatSnackBar ) { } public handleError (error: HttpErrorResponse | any) { this.snackBar.open('Error message: '+error.error.error, 'action', { duration: 4000, }); return throwError(error); } }

Create a service with this:用这个创建一个服务:

custom-snackbar.service.ts

import { Injectable, NgZone } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';

@Injectable()
export class CustomSnackbarService {
    constructor(
      private snackBar: MatSnackBar,
      private zone: NgZone
    ) {
       
    }

    public open(message: string, action = 'success', duration = 4000): void {
        this.zone.run(() => {
          this.snackBar.open(message, action, { duration });
        });
    }
}

Add the MatSnackBarModule to the app.module.ts :MatSnackBarModule添加到app.module.ts

import { MatSnackBarModule } from '@angular/material/snack-bar';

...
imports: [
    BrowserModule,
    AppRoutingModule,
    MatSnackBarModule,
],
...

Also it needs to be run in ngZone: https://github.com/angular/material2/issues/9875它还需要在 ngZone 中运行: https : //github.com/angular/material2/issues/9875

Then in the error-service.ts :然后在error-service.ts

public handleError (error: HttpErrorResponse | any) {
  customSnackbarService.open(error, 'error')
  return throwError(error);
}
   

Use fat arrow ()=> instead of function on the handleErrorhandleError上使用handleError箭头()=>代替函数

public handleError = (error: HttpErrorResponse | any) => {
    this.snackBar.open('Error message: '+error.error.error, 'action', {
      duration: 4000,
    });
    return throwError(error);
  }

The question is about the default code what you write in the "error" function of any observable to make HTTP request and establish a generic action by default in case of get any error HTTP 4xx response from the API (for my particular case, display a MatSnackBar with the error).问题是关于您在任何 observable 的“错误”函数中编写的默认代码,以发出 HTTP 请求并默认建立通用操作,以防从 API 获得任何错误 HTTP 4xx 响应(对于我的特殊情况,显示一个MatSnackBar 有错误)。 Well, i found the solution, ovewriting the ErrorHandle of Angular implementing this: https://angular.io/api/core/ErrorHandler好吧,我找到了解决方案,写了实现这个的 Angular 的 ErrorHandle: https ://angular.io/api/core/ErrorHandler

This is my XhrErrorHandlerService这是我的 XhrErrorHandlerService

 import { Injectable, ErrorHandler, Injector, NgZone } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http'; import { MatSnackBar } from '@angular/material'; @Injectable({ providedIn: 'root' }) export class XhrErrorHandlerService implements ErrorHandler{ constructor( private injector: Injector, public snackBar: MatSnackBar, private readonly zone: NgZone ) {} handleError(error: Error | HttpErrorResponse){ if (error instanceof HttpErrorResponse) { for (var i = 0; i < error.error.length; i++) { this.zone.run(() => { const snackBar = this.snackBar.open(error.error[i], error.status + ' OK', { verticalPosition: 'bottom', horizontalPosition: 'center', duration: 3000, }); snackBar.onAction().subscribe(() => { snackBar.dismiss(); }) }); } } else{ console.error(error); } } }

And this is my ng Module:这是我的 ng 模块:

 import { BrowserModule } from '@angular/platform-browser'; import { NgModule, ErrorHandler } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import * as moment from 'moment'; import { AppComponent } from './app.component'; //ANIMATIONS import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; //ANGULAR MATERIAL import { MaterialModule } from './amaterial.module'; //SERVICES import { AuthService } from './services/auth.service'; import { XhrErrorHandlerService } from './services/xhr-error-handler.service'; //RUTAS import { RouteRoutingModule } from './route-routing.module'; //INTERCEPTOR import { AuthInterceptor } from './http-interceptor/auth-interceptor'; @NgModule({ declarations: [ AppComponent, ], entryComponents: [], imports: [ BrowserModule, BrowserAnimationsModule, MaterialModule, RouteRoutingModule, EntryComponentModule, HttpClientModule, FormsModule, ReactiveFormsModule ], providers: [ AuthService, XhrErrorHandlerService, { provide: ErrorHandler, useClass: XhrErrorHandlerService } { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, ], bootstrap: [AppComponent] }) export class AppModule { }

It is possible to open a snackbar in any service.可以在任何服务中打开小吃店。 The key is a proper way of using handleError() function in catchError() - context of this must be bound with the handler function.关键是在catchError() handleError() function 的正确方法 - this的上下文必须与处理程序 function 绑定。

Add MatSnackBarModule into app.module.ts imports arrayMatSnackBarModule添加到app.module.ts导入数组

import { MatSnackBarModule } from '@angular/material/snack-bar';
...
 imports: [MatSnackBarModule]
...

Use the snackbar in any service, eg MyService like this:在任何服务中使用snackbar ,例如像这样的MyService

import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ApiService } from './api.service';

@Injectable()
export class MyService {
  constructor(
    private api: ApiService,
    private snackBar: MatSnackBar,
  ) {}

  getRegime(): Observable<Regime> {
    return this.api.regime().pipe(
      catchError((err) => this.handleError(err)) //bind the context of 'this' instance with '=>'
    );
  }

  getBranches(): Observable<Branch[]> {
    return this.api.branches().pipe(
       catchError(this.handleError.bind(this)) //bind the context of 'this' instance with 'bind(this)'
    );
  }

  handleError(err: any) {
    this.snackBar.open(`Failed.`, 'Ok', { panelClass: 'warn' });
    return throwError(err);
  }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM