2

I am trying to show a material snackbar for the backend errors in my Angular 5 application.

I tried multiple ways but none worked, seems that the ErrorHandler class needs some special way to call the snackbar correctly.

Can someone please advise how to handle this?

I am getting this error:

Provider parse errors:
Cannot instantiate cyclic dependency! ApplicationRef ("[ERROR ->]"): in NgModule AppModule in ./AppModule@-1:-1
Evaluating main.ts

My custom ErrorHandler class is (without the imports) :

@Injectable()
export class MyErrorHandler implements ErrorHandler {

  constructor(public snackBar: MatSnackBar) {}

  handleError(error) {
    const errorMsg = 'an error has happened';
    this.openSnackBar(errorMsg);
    }

  openSnackBar(message: string) {
      this.snackBar.open(message);
  }
}

This is a stackblitz example to show what I mean

Note:

I have found this error in multiple questions but I can't exactly map the answers to my case

Community
  • 1
  • 1
Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85

1 Answers1

4

Angular loads ErrorHandler before the providers, this is the reason for your error about cyclic dependency.

So you need to inject the MatSnackBar manually, using the Injector, as this way:

import { Injectable, Injector } from '@angular/core';
import { MatSnackBar } from '@angular/material';

@Injectable()
export class MyErrorHandler implements ErrorHandler {

  private snackbar;
  constructor(private injector: Injector) {}

  handleError(error) {
    this.snackBar = this.injector.get(MatSnackBar);
    const errorMsg = 'an error has happened';
    this.openSnackBar(errorMsg);
  }

  openSnackBar(message: string) {
      this.snackBar.open(message);
  }
}

I have modified your stackblitz, now it works.

Kalamarico
  • 5,466
  • 22
  • 53
  • 70
  • 1
    I can't thank you enough! :) Thanks a lot for your valuable help & the excellent answer, also thanks for clearly explaining the reason beside fixing the problem I've been trying to fix it for hours. – Ahmed Elkoussy May 15 '18 at 18:32
  • 1
    Just to improve my understanding of the concept, why could we use the injector in the constructor but not any other dependency injection (like MatSnackBar or my other services) ? – Ahmed Elkoussy May 15 '18 at 18:49
  • 1
    Probably you have a shared module or an independent module to load the material modules. The thing is, in angular Bootstrap, ErrorHandler is processed and injects (I'm talking the previous way, with the cyclic error), after that, when angular bootstrap process the providers, MatSnackBar is injected again. The cyclic message is an alert because maybe angular can find that situation (there is a way to avoid that alert but it's not recommended). Injector it's a bit special, you can read more here: https://toddmotto.com/angular-dependency-injection – Kalamarico May 15 '18 at 18:58
  • 1
    ok, I think you mean `app.module.ts` which is loading most of the modules in my app, I will check the link out, thanks again! – Ahmed Elkoussy May 15 '18 at 19:09
  • 1
    Yes, but don't worry it's typical use injector in an ErrorHandler. But probably the best way is the factory providers, here you can read more about that: https://angular.io/guide/dependency-injection#factory-providers – Kalamarico May 15 '18 at 19:14