28

How to tell Angular 2 to not block the whole application when it encounters an exception?

I'm not sure if it's even possible, because Google didn't enlighten me on this. But it seems critical to any single page web application.

Whenever Angular 2 encounters an exception and throws an error, the complete application becomes unresponsive.

I know that in JavaScript

try {
  doSomething();
}
catch(err) {
  handleErrors(err);
}

might solve the problem.

But I just want to know if there is any Angular specific solution or workaround?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
  • http://stackoverflow.com/questions/37836172/angular-2-doesnt-update-view-after-exception-is-thrown#answer-43796615 – yurzui May 17 '17 at 11:10

4 Answers4

14

On angular 2 final version, you can implement custom ErrorHandler (Angular 2 docs example):

import {NgModule, ErrorHandler} from '@angular/core';

class MyErrorHandler implements ErrorHandler {
  handleError(error) {
    // do something with the exception
  }
}

@NgModule({
  providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
})
class MyModule {}
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Asaf Hananel
  • 7,092
  • 4
  • 24
  • 24
10

UPDATE:

2.0.0 RC.6 changed the name from ExceptionHandler to ErrorHandler and call to handleError:

@Injectable()
class MyErrorHandler implements ErrorHandler {

  handleError(error) {
    // do something with the exception
  }
}


@NgModule({
  directives: [MyApp],
  providers: [
    {provide: ErrorHandler, useClass: MyErrorHandler}
  ]
})
export class AppModule {}

See also this.

ORIGINAL:

Implement a custom exception handler:

@Injectable()
class MyExceptionHandler implements ExceptionHandler {
  call(error, stackTrace = null, reason = null) {
    // do something with the exception
  }
}


@NgModule({
  directives: [MyApp],
  providers: [
    {provide: ExceptionHandler, useClass: MyExceptionHandler}
  ]
})
export class AppModule {}

See also this and this.

I haven't tried myself if this allows the application to continue after an exception, but I think it's worth a try. At least reloading the page automatically should be possible.

Generally, an exception should be handled as close as possible to the cause when there is a way to recover.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 3
    I tried it and successfully redirected to non error prone homepage, which is better than nothing. But I haven't found a way to let the application stay responsive even after exception, which is in general wouldn't be a good way but as a fallback it could be nice to have. – Ankit Singh Feb 06 '16 at 13:48
  • I guess there is no other way than catching the exception earlier. The exception bubbles up to Angular and Angular has no way to know how to handle your custom "bug". It runs your exception handler and exits. – Günter Zöchbauer Feb 06 '16 at 13:50
3

I tried to implement Custom Exception Handler as directed by @GünterZöchbauer

and this worked for me


Bootstrap your application with CustomExceptionHandler.

import {ExceptionHandler} from 'angular2/core';

class _ArrayLogger {
  res = [];

  log(s:any):void {
    this.res.push(s);
  }
  logError(s:any):void {
    this.res.push(s);
  }
  logGroup(s:any):void {
    this.res.push(s);
  }
  logGroupEnd() {
    if(this.res.length) {

      //this section executes if any error is logged by angular. 

      //do your stuff here

      /*e.g

        if(location.pathname !== 'dashboard') {
           window.location.href = '/dashboard'; // condition is required to prevent infinite loop
        }

        */
     }
  };
}

export class CustomExceptionHandler extends ExceptionHandler {
  constructor() {
    super(new _ArrayLogger(), true);
  }

  call(error, stackTrace = null, reason = null) {
    super.call(error, stackTrace, reason);
  }
}

bootstrap(MyApp, [provide(ExceptionHandler, {useClass: CustomExceptionHandler})])
Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
2

I think the issue might occur when you're using RxJS Observables, which unsubscribe when they encounter any error. If that's the case for you, you might need to:

  1. Catch the exception within the .subscribe's onNext handler with try...catch instead of inside onError handler.
  2. Re-subscribe in .subscribe's onError handler.
Michal Leszczyk
  • 1,849
  • 15
  • 19
  • How to access this onNext handler. Could you elaborate the syntax? – Rohit Rane Oct 06 '16 at 10:05
  • @jackOfAll Sure. When you have an Observable object, then you can call a `subscribe` method on it, i.e.: `observable.subscribe(myHandler)`. `subscribe` method actually takes 3 arguments. The first one is called `onNext`, 2nd - `onError` and 3rd - `onCompleted`. You can see more here: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/subscribe.md . Don't hesitate to ask if you have any more questions or if my answer doesn't cover what you meant :) – Michal Leszczyk Oct 07 '16 at 13:43
  • Thanks Michal. I tried wrapping the entire subscribe method in a try catch block. I also tried placing the code withing each callback arguments(onNext and onError, I haven't explored onCompleted ) within try catch blocks. But in each of the case I could not catch the exception! In my case the crash is happening when I get a 404 response from my API and I end up in the onError callback – Rohit Rane Oct 07 '16 at 19:12