typescript - Hur kan jag visa en MatSnackBar från en Service med Angular Material?
Jag använder: Angular V6.1.0, Angular Material V6.4.1
Jag försöker fånga HTTP-felen och visa dem med en MatSnackBar. Jag vill visa detta i varje komponent av min applikation (där det finns en HTTP-förfrågan). Så att jag inte behöver göra upprepad kod
Annars skulle jag behöva upprepa samma kod i varje komponent för att visa MatSnackBar med de insatta felen.
Detta är min tjänst:
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);
}
}Svar #1
Skapa en tjänst med detta:
custom-snackbar.service.tsimport { 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 });
});
}
}
Lägg till MatSnackBarModule i app.module.ts:
import { MatSnackBarModule } from '@angular/material/snack-bar';
...
imports: [
BrowserModule,
AppRoutingModule,
MatSnackBarModule,
],
...
Det behöver också köras i ngZone: https://github.com/angular/material2/issues/9875
Sedan i error-service.ts:
public handleError (error: HttpErrorResponse | any) {
customSnackbarService.open(error, 'error')
return throwError(error);
}
Svar #2
Det är möjligt att öppna en snackbar i vilken tjänst som helst. Nyckeln är ett korrekt sätt att använda handleError()-funktionen i catchError() - kontexten av this måste vara bunden med handlarefunktionen.
Lägg till MatSnackBarModule i app.module.ts imports-arrayen
import { MatSnackBarModule } from '@angular/material/snack-bar';
...
imports: [MatSnackBarModule]
...
Använd snackbar i vilken tjänst som helst, t.ex. MyService på detta sätt:
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);
}
}
