Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch errors that happen when showing an Angular dynamic component?

Tags:

angular

I have a component to display notifications. It has a ViewChild that has a ViewContainerRef.

Based on the type of notification, I display different components in place of that viewChild. This is the code to create and add the component based on the notification type:

private loadInappNotificationItem(messageType: MessageType): void {
  const inappNotificationItemComponent: Type<IInappNotificationItemComponent>
    = this.inappNotificationItemMapping.get(messageType);
  if (inappNotificationItemComponent === undefined) {
    this.hasCustomComponent = false;
    return;
  }

  const componentFactory: ComponentFactory<IInappNotificationItemComponent> =
    this.componentFactoryResolver.resolveComponentFactory(inappNotificationItemComponent);

  this.hasCustomComponent = true;
  const viewContainerRef: ViewContainerRef = this.inappNotificationItemHost.viewContainerRef;
  viewContainerRef.clear();

  const componentRef: ComponentRef<IInappNotificationItemComponent> =
    viewContainerRef.createComponent(componentFactory);

  const component: IInappNotificationItemComponent = componentRef.instance;
  component.notification = this.notification;
}

This works as intended, but now i'd like to show a fallback component, if anything goes bad when displaying the notification component (for example when the structure of the notification property is wrong).

For this i'd need to be able to register a function somewhere, that is called when displaying the viewChild failed for some reason, so that i can then remove it and display a fallback.

I know that i can register a custom ErrorHandler on the Module that contains the component, and i can catch the Errors i'd like to catch there, but in that handler i have no reference to the notification component whose viewChild failed to display.

UPDATE:

I was able to write a class-decorator that will catch every error in every method of my component class, which in turn allowed me to display the fallback when anything in my component class throws an error. Sure, i'd need to decorate all custom components with this, but that's ok, as long as i only need to add this one decorator. (See my my partial answer)

This however did not help with Errors that originate from the template! For example, when accessing a property in the custom components template, that doesn't exist. So, another question that might help solve this one is: how do i catch runtime template errors IN my component (not globally or on module level, as i don't have a reference to the broken component there)

like image 683
Neutrosider Avatar asked May 31 '19 13:05

Neutrosider


People also ask

What is the best way to perform error handling in Angular?

One traditional way of handling errors in Angular is to provide an ErrorHandler class. This class can be extended to create your own global error handler. This is also a useful way to handle all errors that occur, but is mostly useful for tracking error logs.

How does Angular handle response errors?

The basic way to handle errors in Angular is to use Angular's HttpClient service along with RxJS operators throwError and catchError. The HTTP request is made, and it returns the data with a response if anything wrong happens then it returns an error object with an error status code.

Which service in Angular that allows to dynamically load a component?

Angular has its API for loading components dynamically.

How will you handle errors in angular 2 applications?

Angular 2 applications have the option of error handling. This is done by including the ReactJS catch library and then using the catch function. Let's see the code required for error handling. This code can be added on top of the chapter for CRUD operations using http.


1 Answers

@Neutrosider If you refere to random js erros generated by your app code what I would do is eighther wrap the angular hooks from those components into try {} catch statements but this does not look nice. Or create some typescript custom annotations which will act something like this

interface ErrorHandledComponent {
    isInErrorState: boolean;
}

export function HandleComponentErrors() {
    return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const oriiginalHook = target[propertyKey].bind(target);
        target[propertyKey] = (...args) => {
            try {
                oriiginalHook(...args)
            } catch (e) {
                if (isDevMode) {
                    console.error(e);
                }
                target.isInErrorState = true;
            }
        }
    }
}
@Component({
....
template: `<ng-container *ngIf="!isInErrorState">...content<ng-container>
<ng-container *ngIf="isInErrorState">...error content<ng-container>`
})
export class CumponentWithErrorHandling implements {
   isInErrorState: boolean;
   @HandleComponentErrors()
   ngOnInit() {
   ...your custom code
   }
}

And basicly annotate all the angular hooks if that's what you are trying to achieve then you will have a nice render for a js error inside your code implementation or maybe dispatch the error further or log it to your backend. I hope it helps

like image 101
Nicu Avatar answered Oct 07 '22 07:10

Nicu