Shashank
Shashank

Reputation: 2060

Angular 2 - Global Error handler getting executed only when the error is NOT catched

In my Angular application, there is a global error handler and a service responsible for making http calls, having return type as Observable<any>. Some services have handled the errors explicitly and some not.

For those, which has not been catched, the global error (having class 'CustomErrorHandler') runs fine. For the service calls, which has been handled and catched gracefully, the global error doesn't seem to fire.

My question: Is there a way to execute the global error handling irrespective of whether the http service calls has been handled or not?

custom-error-handler.service.ts

@Injectable()
export class CustomErrorHandler implements ErrorHandler {
    constructor(private injector: Injector) { }

    handleError(error) {
        error = error || new Error('There was an unexpected error');
        const loggingService: LoggerService = this.injector.get(LoggerService);
        const location = this.injector.get(LocationStrategy);
        const message = error.message ? error.message : error.toString();
        const url = location instanceof PathLocationStrategy
        ? location.path() : '';

        // get the stack trace, lets grab the last 10 stacks only
        StackTrace.fromError(error).then(stackframes => {
            const stackString = stackframes
                .splice(0, 20)
                .map((sf) => {
                    return sf.toString();
                }).join('\n');

            // log with logging service
            loggingService.error({ message, url, stack: stackString });

        });

        throw error;
    }

}

auth.service.ts

@Injectable()
export class UserAuthService {
    login(emailAddress: string, password: string): Observable<boolean> {
        if (this.isAuthenticated()) {
        return Observable.of(true);
        }

        return Observable.create(observer => {
        this.http.get('http://someurl/login')
            .map(res => res.json())
            .subscribe(
              data => {
                observer.next(this.isAuthorized);
                observer.complete();
              }, err => {
                observer.error(err);
              }
           );
        });
    }

  }

my-component.ts

import { UserAuthService } from '../services/auth.service';

@Component({
    selector: 'my-component',
    templateUrl: './my-component.html',
    styleUrls: ['./my-component.scss']
})
export class MyComponent {
    constructor(private authService: UserAuthService) {}

    handleLogin() {
        this.authService.login(formValues.emailAddress, formValues.password)
            .subscribe(res => {
                console.log('Logged In');
            }, err => {
                console.log('Logging Failed'); 
                // Global Error DOESN'T fire here as the Error has been handled
            });
    }

    handleLoginPart2() {
        this.authService.login(formValues.emailAddress, formValues.password)
            .subscribe(res => {
                console.log('Logged In');
            }); // Global Error does fire here as the Error has NOT been handled
    }
}

Upvotes: 1

Views: 677

Answers (1)

Shashank
Shashank

Reputation: 2060

I was able to resolve the issue myself, by creating a HttpClient which inherits from Http.

By doing this I am able to handle the error gracefully.

http-client.service.ts

import { ConnectionBackend, Http, RequestOptions, RequestOptionsArgs, Response } from '@angular/http';

@Injectable()
export class HttpClient extends Http {
  http;

  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  get(url, options?: RequestOptionsArgs): Observable<Response> {
    return super.get(url, options)
      .catch(this.handleError);
  }

  private handleError(errorRes: Response | any) {
    return Observable.throw(retError);
  }
}

Upvotes: 1

Related Questions