Detecting changes in custom ExceptionHandler may cause delays in recognition

Currently, I am working on integrating a personalized ExceptionHandler in an Angular 2 application that sends unhandled errors to a customized AlertsService. The objective is to enable the main App component to subscribe to the alerts provided by the AlertsService so that it can show the errors in the user interface.

The issue I'm encountering is that when errors are reported to the AlertsService by the custom ExceptionHandler, they do not immediately show up in the UI until another error occurs. This leads to the UI always being one alert behind what is actually available from the AlertsService.

I suspect that this behavior might be related to change detection and the unique case of the ExceptionHandler, but I am unsure about the next steps to take. Seeking assistance from the Angular 2 experts!

Find a snippet of the code below, plunk here:

import { Component, ExceptionHandler, Injectable, OnInit, provide } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Subject } from 'rxjs/Subject'

export interface Alert {
  message: string;
}

@Injectable()
export class AlertsService {

  private alertTriggeredSubject = new Subject<Alert>();

  alertTriggered = this.alertTriggeredSubject.asObservable();

  triggerAlert(message: string) {
    this.alertTriggeredSubject.next(<Alert>{ message: message });
  }

}

@Injectable()
export class CustomExceptionHander {

  constructor(private alertsService: AlertsService) { }

  call(exception, stackTrace = null, reason = null) {
    this.alertsService.triggerAlert(exception.originalException);
    console.error('EXCEPTION:', exception);
  }
}

@Component({
  selector: 'child-component',
  template : `
  <h3>Child</h3>
  <div id="child">
    <button (click)="breakMe()">Break Me!</button>
    <div>Alerts Sent:</div>
    <ul><li *ngFor="let error of errors">{{error}}</li></ul>
  </div>`
})
export class ChildComponent {

  errors: string[] = [];
  numErrors = 0

  breakMe() {
    this.numErrors++;
    let error = `I broke it (${this.numErrors})`;

    // The error added to the array below is never reflected in the 
    // "Alerts Sent:" <ul>...not sure why
    this.errors.push(error);
    console.info('ChildComponent.errors', this.errors);

    // Simulate unhandled exception
    throw new Error(error);
  }
}

@Component({
  selector: 'my-app',
  template : `
  <h3>Parent</h3>
  <div id="parent">
    <div>Alerts Received:</div>
    <ul><li *ngFor="let alert of alerts">{{alert.message}}</li></ul>
    <child-component></child-component>
  </div>`,
  directives: [ChildComponent]
})
export class App implements OnInit {

  constructor(private alertsService: AlertsService) { }

  alerts: Alert[] = [];

  ngOnInit() {
    this.alertsService.alertTriggered.subscribe(alert => {
      this.alerts.push(alert);

      // Alert gets received, but is not reflected in the UI
      // until the next alert is received, even thought the 
      // alerts[] is up-to-date.
      console.info('App alert received:', alert);
      console.info('App.alerts:', this.alerts);
    });
  }
}

bootstrap(App, [
    AlertsService,
    provide(ExceptionHandler, { useClass: CustomExceptionHander })
]).catch(err => console.error(err));

Answer №1

update ErrorHandler has been changed from ExceptionHandler. See more at:

original

The change detection process does not occur at the end of the click event if an error is thrown by the handler.

Manually invoking change detection can be complex due to the dependency cycle between ApplicationRef, ExceptionHandler, and DI's inability to resolve cyclic dependencies.

A workaround is to inject the Injector instead of ApplicationRef and obtain AplicationRef imperatively as follows:

constructor(private alertsService: AlertsService, injector: Injector) { 
  setTimeout(() => this.appRef = injector.get(ApplicationRef));
}

Then, in the call method, you can trigger change detection like so:

call(exception, stackTrace = null, reason = null) {
  this.alertsService.triggerAlert(exception.originalException);
  this.appRef.tick();
  console.error('EXCEPTION:', exception);
}

Plunker example

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Turn off VSCode's auto-suggestion feature for inserting curly braces

Recently, I've been facing some issues with the autocomplete feature in vscode. After hitting enter, the autocomplete seems to disable itself, requiring me to press Control+Space to make it pop up and select an option like in this image: https://i.s ...

How to create an array of objects in Angular 2

Can someone please help me understand how to set up an array of objects so that I can add items to it later on? Here's what I currently have: tab: [{tel:number, name:String}]; ...

Sharing an angular app URL containing query parameters with multiple users

I am in need of a feature that allows me to transfer the filter settings on a page to another user. For instance, if I apply certain filters on a specific page, I would like to share the URL with those filters already applied to other users. ...

Is it possible in Typescript to pass method signature with parameters as an argument to another method?

I am working on a React app where I have separated the actions into a different file from the service methods hoplite.actions.ts export const fetchBattleResult = createAsyncThunk<Result>( 'battle/fetchBattleResult', HopliteService.battleRe ...

How can you specify the active route in Angular?

I am curious about whether it is possible to set the active route from a script instead of just from the HTML template. Let me provide an example: @Component({ template: `<input type="button" (click)="back()" value="back" ...

Error with React Query Mutation and TypeScript: The argument '{ surgeryID: any; stageTitle: any; }' cannot be assigned to a parameter of type 'void'

Utilizing react-query for fetching and posting data to my database on supabase has been really helpful. I took the initiative to create a custom hook specifically for adding records using react-query: export function useAddSurgeryStage() { const { mutate ...

What is the reason for the restriction on CORS with a custom scheme handler in AddCrossOriginWhitelistEntry or IsCorsEnabled?

Situation Our setup involves utilizing CefSharp (v57.0) to host an Angular2 (v4.2) application that shares components between a web application and game UI client. The goal is for the game client to send requests to the server from within the CEFSharp con ...

Encountering an issue while attempting to retrieve a key from an Object within an Observable using async functionality

I have a seemingly basic and simple Object that I retrieve using Rx and would like to display a portion of it on screen. I removed all HTML and simply added {{ structure$ | async | json }}, with structure$ being the name of the Observable in my component, ...

Issue with CSS not appearing in Google Chrome's coverage tab

As I delve into analyzing the extent of unused CSS on my webpage, I encounter a challenge. The webpage is crafted in Angular 7, with CSS incorporated through the angular.json build configuration. The css appears to be added to the head of the html file, e ...

The Validator.js module cannot be located - Unable to resolve 'http' in the client

Struggling with integrating the amadeus-node package into an angular 10 project. When I add the following line: const Amadeus = require('amadeus'); I encounter this error: ERROR in ./node_modules/amadeus/lib/amadeus/client/validator.js Module ...

Angular Custom Input Form: Tailored to Your Specific Needs

Need help modifying an input field? Here's how: <input type="text" formControlName="name" placeholder="placeholder" (keypress)="function" (focus)="function" You can create a component to achieve the same functionality by using this template code: ...

Styling with Css Attributes and Text Formatting Styles

I am working with a custom textStyle that is of type TextStyle, coming from react-native types, or React.CSSProperties. I want to apply this styling to an html span element using the style attribute. The style attribute only accepts types of React.CSSPrope ...

Issue with Angular 8 Animations when loading a module lazily - Encountered Synthetic Property Error

I currently have 2 different modules in my project, namely the app.module and a lazy.module. The lazy.module is specifically designed to be lazy loaded into the main app.module through routing mechanisms. const routes: Routes = [ { path: '', lo ...

After installing Microsoft.AspNetCore.SpaTemplates::*, the Angular template seems to be missing

Today I decided to start using .Net and successfully installed the SDK. Following instructions, I ran the CLI command to install the SPA template: dotnet new --install Microsoft.AspNetCore.SpaTemplates::* Although the command ran without any errors, I co ...

Remove the color options from the Material UI theme

Can certain color types be excluded from the MUI palette in MUI v5? For example, can background and error colors be removed, allowing only colors defined in a custom theme file to be used? I attempted using 'never' but it did not provide a solut ...

Tips for adding items to a Form Array in Angular

I am working on a project with dynamic checkboxes that retrieve data from an API. Below is the HTML file: <form [formGroup]="form" (ngSubmit)="submit()"> <label formArrayName="summons" *ngFor="let order of form.controls.summons.controls; let i ...

On the subsequent iteration of the function, transfer a variable from the end of the function to the beginning within the same

Can a variable that is set at the end of a function be sent back to the same function in order to be used at the beginning of the next run? Function function1 { If(val1.id == 5){ Console.log(val1.id val1.name) } else{} Val1.id = 5 Val1.name = 'nam ...

Generating tables with ngFor in Angular 2

Is it possible to generate a table in Angular 2 with a dynamic number of columns by utilizing a loop based on the specified number? Specifically, how can we create a table without a fixed number of columns? ...

Tips for accessing a variable from a Global service in Ionic

I am currently working on developing an app using Ionic but experiencing some difficulties. I encountered an issue while trying to access a variable from a global service when it is imported to another page. Here is an example of the Global service (backen ...