Error encountered numerous times within computed signals (angular)

I have incorporated signals into my Angular application.

One of the signals I am using is a computed signal, in which I deliberately introduce an exception to see how it is handled. Please note that my actual code is more intricate than this example.

  public test: Signal<string> = computed(() => {
    throw new Error(`Testing throwing exception`);
    return 'foo';
  });
  <p>{{ test() }}</p>

Upon checking the console, I notice that the exception is thrown multiple times (at least 15 times) https://i.sstatic.net/IkU4Q.png

To handle unexpected exceptions, I have integrated bugsnag for error reporting. However, I observe that bugsnag reports the same exception multiple times instead of just once.

One approach that seems to work is to include a try-catch block within my computed function and manually report to bugsnag like so:

  public test: Signal<string> = computed(() => {
    try {
      throw new Error(`Testing throwing exception`);
      return 'foo';
    } catch (error) {
      Bugsnag.notify(error as NotifiableError);
      return '';
    }
  });

Is there a more efficient way to handle such scenarios? It feels like handling exceptions within a "computed signal" is a common requirement.

Answer №1

Whenever an error occurs in the computed function, the error is memorized just like the computed value in regular usage. So, if you access the computed signal again and no dependency has changed, the computation function won't run again, and the memorized error will be thrown once more.

You can observe this behavior in the following example :

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button type="button" (click)="handleClick()">
      Click me
    </button>
    {{vComputed()}}
  `,
})
export class App {
  handleClick() {
    console.log('clicked');
  }

  vComputed = computed(() => {
    console.log('execution of computed function');
    throw Error('error');
  });
}

The message execution of computed function appears only once because there are no dependencies causing a re-execution of the computed function. The error is thrown each time the computed signal is accessed (triggered by a change detection event such as clicking the button).

In your example, you might see the exception multiple times due to multiple change detections triggering a refresh of the view and reading the computed signal again.

To handle an error in a computed signal, you have two options:

  1. Capture the error within the computed function (like in your example) and return a fallback value.
@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button type="button" (click)="handleClick()">
      Click me
    </button>
    {{vComputed()}}
  `,
})
export class App {

  ...

  vComputed = computed<number>(() => {
    console.log('execution of computed function');
    try {
      throw Error('error');
    } catch(e) {
      return 0;
    }
  });
  1. Retrieve the computed value in a method instead of directly in the template.
@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button type="button" (click)="handleClick()">
      Click me
    </button>
    {{getValue()}}
  `,
})
export class App {

  ...

  getValue() {
    try {
      return this.vComputed();
    } catch (e) {
      return 0;
    }
  }

There's a slight distinction between both solutions - in the second one, the catch block will be executed every render (each time getValue function is called), whereas in the first solution, the fallback value is memoized so the catch block runs only once.

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

ejs-lineargauge major divisions and minor divisions centered

I've been trying to align majorTicks and minorTicks in the middle of the axis, but so far I haven't found a solution despite searching and googling extensively. Here's a snippet of my code: majorTicks: { height: 12, interval: 1, width ...

Generate a Jest dummy for testing an IncomingMessage object

I am facing a challenge in writing a unit test for a function that requires an IncomingMessage as one of its parameters. I understand that it is a stream, but I am struggling to create a basic test dummy because the stream causes my tests to timeout. : T ...

When switching tabs, Ion-select should not reload the selected name

Whenever I switch tabs and then return to the previous tab in Ionic, the select field that was previously set becomes null, even though the page is still loading and the variable is populated. <ion-header color="primary"> <ion-navbar> &l ...

Modules that are imported in the AppModule will not be accessible in other modules

Suppose this represents my AppModule: @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, MaterialModule, HomeModule ], exports: [ MaterialModule ], providers: [], bootstrap: [App ...

Is there a method we can use to replace fixture fields with data created during the test case to produce a dynamic payload? (Already attempted existing solution)

I am new to using Cypress and I'm wondering if there is a way to generate a dynamic payload by replacing values in a JSON file with values generated programmatically in a Cypress test. This is similar to what we do in Rest Assured by substituting %s i ...

Using JSON as a variable solely for determining its type and guaranteeing that the import is eliminated during compilation

In my TypeScript backend project with Node as the target runtime, I have a JSON file that is auto-generated within my repository. I use the following code to import the JSON file in order to get the type of the JSON object: import countries from '../g ...

Is it possible to transfer the security measures from Angular 6 to Angular 9?

Is it necessary to update my Angular project from version 6 to 7 before moving on to the latest version, or can I upgrade directly to the most recent version of Angular? ...

What steps are necessary to ensure that the extended attribute becomes mandatory?

Utilizing Express, I have set specific fields on the request object to leverage a TypeScript feature. To achieve this, I created a custom interface that extends Express's Request and includes the additional fields. These fields are initialized at the ...

Steps to resolve the error "Cross-Origin Request Blocked: The Same Origin Policy prohibits reading the remote resource" in a project using Angular and .NET

Whenever I make an HTTP GET request to our API endpoints, I encounter errors indicating that the CORS header 'Access-Control-Allow-Origin' is missing. Our system consists of a SQL Server database connected to a .NET API with an Angular 7 front e ...

Obtain a filtering dropdown list directly from the database within Ag-grid

Currently in my interface, I am attempting to implement a filter for the FOLDER column. This filter is supposed to retrieve data from the database and present it in a dropdown checkbox within that column. The filtering should be based on the selected data. ...

What is the best way to set the minDate and maxDate of the NgbDatePicker in the main component so that the settings can be applied

Within my Angular 4 project, I have integrated Ng-bootstrap (v1.1.0) which includes multiple date pickers across different modules. I am looking to enforce a global maxDate configuration for all these instances. Below is an overview of my folder structure: ...

How to set the default option in a select dropdown using Angular and Types

It's been a while since I last worked with Angular and now I'm tasked with working on an existing system. I introduced an NgModal dialog to send text messages, designed as shown here: https://i.sstatic.net/67U1M.png Below is the code snippet I ...

Unit testing Firebase function with Jest for mocking

Currently, I am in the process of developing unit tests and facing challenges with mocking Firebase functions while specifying the return type upon calling them. The code snippet below illustrates what I intend to mock (account.service.ts) and provides ins ...

What is the best way to attach a button to a mat-drawer?

I am facing an issue with aligning a button to a mat drawer located to the right of the screen to ensure a clear overall design. Check out this example How can I achieve this alignment? My current approach involves placing the button inside the drawer an ...

The timezone plugin in day.js may sometimes generate an incorrect date

For a while, I've been using dayjs in my angular project to convert timestamps from UTC to localtime. However, after my recent update, this functionality stopped working. This isn't the first issue I've encountered with dayjs, so I decided t ...

The modal functionality in AngularJS doesn't seem to be functioning properly

I am currently working on an Angular application where I want to implement a button that, when clicked, will open a pop-up window displaying a chart. Below is the button code: <div style="padding-top:50px;padding-left:10px;"> <button type="butto ...

Ways to restrict data types within function parameters

Can you validate types of one argument based on another argument in functions? Consider this example: interface Data { id?: number; name?: string; } let data : Data = {}; // I am unsure how to make the "value" argument strict function update(field : ...

Ways to verify that the Google Analytics code is functioning properly within an Angular 2 application

I'm just getting started with Google Analytics and I'm attempting to integrate it into my Angular 2 project. Here's how I've set it up: app.component.ts import { Component } from '@angular/core'; import {Router, NavigationEn ...

Express and Angular 2 Integration in package.json

Hello, I am new to learning Angular 2 and have a better understanding of Express. One thing that is confusing me is the package.json file, particularly the "start" part. Here is my package.json when I only had Express installed: { "name": "Whatever", ...

"Angular EventEmitter fails to return specified object, resulting in undefined

As I work on a school project, I've encountered a hurdle due to my lack of experience with Angular. My left-nav component includes multiple checkbox selections, and upon a user selecting one, an API call is made to retrieve all values for a specific " ...