Is it possible to utilize Angular Signals for storing a Map data structure?

I've just started exploring the new Signals API in Angular. I was informed that data should be treated as immutable when using signals.

Now, I am unsure if it is possible to implement something similar with JS Maps:

// code within my service.

// Utilizing a Map to store messages in an object and retrieve them by queue name.
messages = signal(new Map<string, Object>());

queryForMessagesInQueue(queue) {
  this.httpClient.get('...').subscribe((newMessagesArray) => {
    const messages = this.messages().get(queue) || {};
    // Checking if newMessages already exist in the message object
    let addedMessages = 0;
    newMessagesArray.forEach((newMsg) => {
      const messageExists = !!messages[newMsg.id]

      if (messageExists == false) {
        messages[newMsg.id] = newMsg;
        addedMessages++;
      }
    });

    if (addedMessages !== 0) {
      this.messages.update((msgMap) => msgMap.set(queue, messages));
    }
  });
}

In my components, I have implemented the following:

export class MyComponent {
   private service = inject(MyService)

   messages = service.messages; // references the service signal.
}

Am I correctly utilizing it?

Can signals integrate seamlessly with data structures like JS Maps? Will change detection function properly?

Appreciate your assistance in advance.

Answer №1

When using signals, the default behavior is to use referential equality (=== comparison). In the context of this.messages.update, you are essentially returning the same instance of a Map. As a result, during the equality check, both the "old" and "new" values of the Map point to the same reference.

To address this issue, it is necessary to return a new instance of the Map for your code to function correctly. Additionally, there seems to be a redundant line of code msgMap.set(queue, messages) as values have already been added to messages, resulting in setting the same reference again.

The revised code snippet would resemble the following:

messages = signal(new Map<string, Object>());

queryForMessagesInQueue(queue) {
  this.httpClient.get('...').subscribe((newMessages) => {
    const messages = this.messages().get(queue) || {};
    const addedMessages = newMessages.filter((newMsg) => !!messages[newMsg.id]);
    if (addedMessages.length) {
      addedMessages.forEach((addedMsg) => messages[addedMsg.id] = addedMsg);
      this.message.update((msgMap) => new Map(msgMap));
    }
  });
}

Lastly, I would suggest changing Object to either Record<string, Message> or utilizing an index signature such as { [messageId: string]: Message }.

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

PHP ordering values of an array in natural sequence

I am encountering an issue where I need to normalize/sort values in an array in natural order after removing an item. Let's look at an example. Here is the initial array: { [313]=> int(2) [303]=> int(1) [295]=> int(3) [290]=> int(4) } T ...

What is the TypeScript counterpart of ParentClass.this?

Given the Java code snippet above, how would you achieve the same functionality in TypeScript as ParentClass.this.a? class ParentClass{ a: number = 1; class ChildrenClass{ b: number = 2; run(){ this.b = parentInstance.a; // Assuming &apo ...

Creating dynamic lists in Angular with ngFor: A step-by-step guide

I am currently working on an Angular 7 application and have a component that retrieves a JSON array. @Component({ selector: 'app-indices-get', templateUrl: './indices-get.component.html', styleUrls: ['./indices-get.component ...

Limiting the Rate of Requests to a TCP Server using net.Server

I've been utilizing net.Server as my TCP server. Is there a way to impose a message rate limit? I managed to find solutions for enforcing rate limits in Express (express-rate-limit) and Websocket (websocket-rate-limit), but nothing specifically for ...

Remove properties that are not part of a specific Class

Is there a way to remove unnecessary properties from the Car class? class Car { wheels: number; model: string; } const obj = {wheels:4, model: 'foo', unwanted1: 'bar', unwantedn: 'kuk'}; const goodCar = filterUnwant ...

What are the best scenarios for implementing modules, components, or standalone components in Angular 17?

Apologies if this question has been posed before, but I'm still navigating my way through Angular and could use some guidance on when to utilize modules, components, or stand-alone components. For instance, if I am constructing a modest website consi ...

Creating a package containing an Angular 2 application combined with Express

I recently completed a regular Angular CLI project using webpack for production. After bundling the project, I transferred the contents of the dist folder to another project where Express was installed. var express = require('express'); var app ...

Service error: The function of "method" is not valid

In one of my Angular 2 applications, I have a class that contains numerous methods for managing authentication. One particular method is responsible for handling errors thrown by the angular/http module. For example, if a response returns a status code o ...

Encountering an error with Angular 7: "global is not defined" issue while trying to include a package

While developing an Angular 7 application, I encountered an issue after adding a package using npm install dragula --save and importing it into the pollyfills.ts file. The error message I received was: index.js:2 Uncaught ReferenceError: global is not d ...

What is the best way to limit a generic argument to only those that are subclasses of a class/constructor that implements a particular interface

I have a function that needs to accept a generic argument type which is constrained to implement a specific interface. I achieved this by defining the interface, an abstract stub class implementing the interface, and using the typeof operator to reference ...

Seeking assistance with TypeScript promises

Just starting out with typescript and nodejs, but I've got to tackle some issues in the typescript code. I'm looking to execute an ECS one-off task using Pulumi. I have the documentation on how to run the task from the taskDefinition, which can ...

Learn how to retrieve the index using PrimNG's TurboTable in conjunction with Angular version

Having trouble finding the correct way to display an index with Angular 6 and PrimeNG turbo table. This is what I have tried so far: <p-table [value]="timecards"> <ng-template pTemplate="body" let-timecard let-i="index"> <tr><t ...

Avoid allowing generic types to be overwritten in Typescript

Is there a way to ensure that the layoutKey remains as type L (specifically IOfficialLevelLayouts) even when passing in other values? Every time I provide a value, it seems to override the desired type. https://i.sstatic.net/YfH6k.png https://i.sstatic.ne ...

Identifying Classifications Based on Input Parameters

I'm encountering some difficulty in typing a function that calls an external API and returns data based on the parameters sent. Here is what I have so far... import axios from 'axios'; interface IGetContactArgs { properties?: string[]; } ...

What is the best way to retrieve the attribute value of an element using Angular 2?

I am working with an HTML span that contains two hyperlinks. <span><a href="http://appcarvers.cloudaccess.host/index.php?Itemid=207" alt="Shirley Setia">Shirley Setia</a><i class="fa fa-caret-right"></i> <a href="http:// ...

"Error: Retrieving the body data from the Express request

I am having trouble retrieving the JSON data using TypeScript in the req.body. It keeps showing up as undefined or an empty object. const signUpUser = ({ body }: Request, res: Response): void => { try { res.send(body) console.log(body) } cat ...

Ongoing state configuration in a React hook

My custom hook: export function useToken2() { const { data: session, status } = useSession(); const [token, setToken] = useState<string | null>(null); useEffect(() => { if (status === 'authenticated' && session?.accessToken) { ...

Error message when using an ionic search bar: "Encountered an issue with reading property srcElement, it

initializeItems() { this.items = this.productos; } getItems(searchbar) { this.initializeItems(); // setting 'q' to the value of the searchbar var q = searchbar.srcElement.value; // if the value is empty, do not filter ...

What is the process for obtaining the Angular.json file for my NX Workspace?

Looking to develop a fresh Angular web application within my NX Workspace, with plans to eventually convert it for iOS and Android using Capacitor. After setting up the nx monorepo, I proceeded to generate a new Angular application by running the command ...

Implementing the 'keepAlive' feature in Axios with NodeJS

I've scoured through numerous sources of documentation, Stack Overflow threads, and various blog posts but I'm still unable to make the 'keepAlive' functionality work. What could I be overlooking? Here's my server setup: import ex ...