0

I would like to have custom errors in my Angular2 app. Thus I have extended ErrorHandler in my component:

import { Component, ErrorHandler, OnInit } from '@angular/core';
import { GenericError } from './generic-error.component';

@Component({
    selector: 'custom-error-handler',
    templateUrl: 'app/error-handler/custom-error-handler.component.html?' + +new Date()
})

export class CustomErrorHandler extends ErrorHandler {
    errorText: string;

    constructor() {
        super(false);
    }

    ngOnInit() {
        this.errorText = 'Initial text!';
    }

    public handleError(error: any): void {
        if (error.originalError instanceof GenericError) {
            console.info('This is printed to console!');
            this.errorText = "I want it to print this in the template!";
        }
        else {
            super.handleError(error);
        }
    }
}

My template simply contains:

<span style="color:red">{{errorText}}</span>

First I see "Initial text!" in the template as set in ngOnInit. That's as expected.

I can then throw a new exception like this from a different component:

throw new GenericError();

and it hits the code with handleError and prints to console but it doesn't update my template errorText with:

"I want it to print this in the template!"

It's like it ignores my template, when inside the handleError function.

What could be the problem here?

* ADDED MORE INFORMATION *

I thought I should add some more information. So here is the module I made for CustomErrorHandler (maybe the problem is with the providers?):

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

import { CustomErrorHandler } from './custom-error-handler.component';

@NgModule({
    declarations: [
        CustomErrorHandler
    ],
    imports: [
        CommonModule
    ],
    exports: [
        CustomErrorHandler
    ],
    providers: [
        { provide: ErrorHandler, useClass: CustomErrorHandler }
    ]
})
export class CustomErrorModule { }

There is indeed only one instance of the CustomErrorHandler (I checked with the Augury Chrome plugin).

For completeness, here is is the GenericError component:

export class GenericError {
    toString() {
        return "Here is a generic error message";
    }
}
brinch
  • 2,544
  • 7
  • 33
  • 55
  • Where are you including ? – raven Apr 10 '17 at 21:33
  • I include that in my app-component template. – brinch Apr 10 '17 at 21:36
  • 1
    It sounds like whatever component your throwing the error from is creating it's own instance of the component. Maybe try using a tool like Augury to inspect the scope hierarchy and make sure the component's a child of the one throwing the error. Or maybe this needs to be in a service so it's easier to share data between components. Hope this helps some. – chairmanmow Apr 10 '17 at 23:16
  • There is only one instance of CustomErrorHandler (I checked with Augury). By the way I updated the question with some more information. – brinch Apr 12 '17 at 07:01
  • Where do you call `handleError`? – eko Apr 12 '17 at 07:02
  • 1
    You have one instance of service and one instance of component. Check constructors calling – yurzui Apr 12 '17 at 07:02
  • 1
    Create two different classes. One for component and one for service. Then inject service in component. – yurzui Apr 12 '17 at 07:04
  • Anyway when it will be done you will run into another problem. When an error occurs angular makes state of view as Errored after that your component won't be able to update view. Indeed you can manually reset state and probably it will work – yurzui Apr 12 '17 at 07:05
  • @yurzui: not sure I follow what you mean exactly. Could you show in a code example? – brinch Apr 12 '17 at 08:36
  • @echonax: handleError is not called directly by me, but is executed when I throw GenericError. This is because I extend Angular's ErrorHandler. – brinch Apr 12 '17 at 10:32
  • Inject `ApplicationRef` to `CustomErrorHandler` (the service) and call `appRef.tick()` after you updated the error text. – Günter Zöchbauer Apr 12 '17 at 10:33
  • @GünterZöchbauer: could you show an example of this is an answer? Thanks :-) – brinch Apr 12 '17 at 10:35
  • http://stackoverflow.com/questions/37793276/angular-2-custom-exceptionhandler-change-detection-lag/37793791#37793791 – Günter Zöchbauer Apr 12 '17 at 10:36
  • @GünterZöchbauer: but the problem is not change detection, but that when inside handleError it cannot see my template. – brinch Apr 12 '17 at 12:06
  • Hard to tell. I can't see from your code how template and service are connected. I'd move the `errorText` out of the `ErrorHandler` to a service with an observable, inject the service to the `ErrorHandler` and the component where you want to display `errorText` and pass error text along using the observable in the shared service. – Günter Zöchbauer Apr 12 '17 at 12:31

1 Answers1

0

The solution was to add a service as suggested in the question's comment track. This way I can set the property in the component and eventually show it in the template.

I created the service, so that it has a function which takes one parameter. Injected the service, call the service's function from the handleError in the component function, and send the text I want in the template as the parameter. Then I use an observable, to get the text back to the component.

In the constructor of the component, I added this observer.

let whatever = this.cs.nameChange.subscribe((value) => {
  setTimeout(() => this.errorText = value);
});

I needed to add the setTimeout, or else it would not update the template before the second time the observable was changed.

Phew! The Angular team should make this global exception handling easier in future releases.

brinch
  • 2,544
  • 7
  • 33
  • 55