App.component.ts not receiving any values on subscribing to custom Error handler stream


#1

Earlier, I have implemented a custom error handler in place of the default IonicErrorHandler that will send error logs to a Third-party logging service. That part is working great, until now I would like to take advantage of this custom error handler to trigger an alert popup on error that notifies the users the app is about the restart, so that the users won’t be stuck on an error screen.

I would like to trigger this alert popup in the app.component.ts, as it has access to an instance of NavController (to setRoot back to the Login Page) and SplashScreen (loading screen while the app is being refreshed on window.location.reload()). However it looks like app.component.ts is not receiving any error values being dispatched by my errorHandler Subject on this.errorSource.next(error), triggered by a manual throw button in development. Anyone has any idea why is that?

If I’m subscribing to the errorStream$ locally within the class GlobalErrorHandler it works as expected. But I won’t have access to the NavController when assigning to my Restart handler in the Alert box.

Thanks.

app.module.ts

import { ErrorHandler } from '@angular/core'
import { GlobalErrorHandler } from './error-handler'

@NgModule({
 declarations: [
   App
   ...
 ],
 ...
 providers: [
  { provide: ErrorHandler, useClass: GlobalErrorHandler },
 ]
})
export class AppModule {}

error-handler.ts

import { ErrorHandler, Injectable } from '@angular/core'
import { Subject } from 'rxjs/Subject';

@Injectable()
export class GlobalErrorHandler extends IonicErrorHandler implements ErrorHandler {
 
  private errorSource = new Subject<Error>();
  errorStream$ = this.errorSource.asObservable();
  constructor() {
    super()
  }

  handleError (error: any) {
    if(error) {
      logger.error(error);
      this.errorSource.next(error);
    }
  }

app.component.ts

@Component({
 templateUrl: 'app.html',
 provider: [ GlobalErrorHandler ]
})
export class App {
 constructor ( private platform: Platform,
               private statusBar: StatusBar,
               private nav: NavController,
               private splashScreen: SplashScreen
               private alertCtrl: AlertController,
               private errorHandler: GlobalErrorHandler
              
  ) {
   platform.ready().then(() => {
     this.errorSubscription = this.errorHandler.errorStream$.subscribe(error => {
       console.log("Error received") // Never receive any errors
       this.presentAlert();
     })
   })
  }

  ngOnDestroy() {
    this.errorSubscription.unsubscribe();
  }
 
}


#2

Get rid of this line. It is giving you a different GlobalErrorHandler instance in your app component than the rest of the app is seeing.


#3

I tried removing this line, but now it’s giving me a Error: No provider for GlobalErrorHandler! when I’m injecting it to my app.component.ts


#4

Add GlobalErrorHandler to the providers of your app module instead.

Won’t work as intended, keep reading thread.


#5

So in app.module.ts, instead of

 providers: [
  { provide: ErrorHandler, useClass: GlobalErrorHandler },
 ]

I just add GlobalErrorHandler directly ?? Does this overwrite the original ErrorHandler from Angular?

providers: [
  GlobalErrorHandler
 ]

#6

Actually, now that I think about it a bit more, that won’t work either, as useClass won’t give us the same instance.

How about this: leave what you have in your app module as is, and change the way you inject the error handler in the app component to be just an ErrorHandler, and then cast it to GlobalErrorHandler in order to access the error stream.


#7

Could you provide an example on how to inject the ErrorHandler and cast it to my custom GlobalErrorHandler?? Couldn’t find examples online so a few lines of example code would be greatly helpful. Thanks a lot


#8
export class AppComponent {
  constructor(private eh: ErrorHandler) {
    let geh = eh as GlobalErrorHandler;
    // now we can access geh.errorStream without tsc complaining
  }
}

#9

Working Now! Thanks a lot :slight_smile: