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

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

}

Relaterade artiklar