Managing Angular signals: updating an element in an array that belongs to an object

Could it be that I am overcomplicating things by using complex signals? Please advise if what I am attempting to achieve is not a suitable use-case for Angular's Signals. However, I strongly believe that it should be achievable!

I have a service in place to manage the state of an order. The order class includes various properties, one of which is an array of OrderItems.

I've defined a signal for the Order as

PackingOrder = signal<order>(orderFromDB);
, and while I can access it without any issues, I'm struggling to figure out how to update a specific OrderItem within the order.

Given a Signal containing an Order object structured with classes like below, how can one update, for example, the 'packed' property of a particular OrderItem based on its id?

 export class Order {
  id: number; 
  customer: string;
  orderItems: OrderItem[];
}

 export class OrderItem {
  id: number; //USING THIS TO IDENTIFY THE ITEM...
  produceName: string;
  unitQty: number;
  container: string;
  yield: number;
  packed: number; //<--HOW TO UPDATE THIS?
  complete: boolean;
}

I have scoured for solutions but all I could find were related to updating arrays or simpler objects in signals. I haven't been able to adapt those answers into a workable solution for this scenario, hence why I am reaching out here!

Answer №1

It appears that the issue arises when cloning a class using object destructuring, resulting in the loss of the class instance which needs to be preserved.


PackingOrder = signal<Order>(hardCodedOrder);

constructor() {
  effect(() => {
    console.log('order changed', structuredClone(this.PackingOrder()));
  });
}

ngOnInit() {
  setTimeout(() => {
    this.PackingOrder.update((order: Order) => {
      const foundItem = order.orderItems.find(
        (item: OrderItem) => item.packed === 2
      );
      if (foundItem) {
        foundItem.unitQty = 10000;
        // Trigger a signal change by returning a clone after updating.
        return order.clone();
      }
      return order;
    });
  }, 5000);
}

My approach involves using the update method to modify values within the signal, providing easy access to the order state.

We locate and update a specific order item using find, ensuring its existence before changing the property (packed updated to 10000).


Note: Non-primitive data types like object and array are stored as references in memory. The signal only detects changes when the actual value is altered, requiring a shift in memory location.


To retain the class prototype while creating a new instance, I implemented a clone method within the class instance. This method generates a new instance with identical data.

export class Order {
  id: number; 
  customer: string;
  orderItems: OrderItem[];

  constructor(id: number, customer: string, orderItems: OrderItem[] = []) {
    this.id = id;
    this.customer = customer;
    this.orderItems = orderItems;
  }

  clone() {
    const clone = Object.assign({}, this);
    return Object.setPrototypeOf(clone, Order.prototype);
    // Uncomment below code for an alternative approach.
    // return new Order(this.id, this.customer, this.orderItems);
  }

Now, utilizing the clone method within the update function triggers a refresh in the signal following data updates.

The use of structuredClone ensures accurate snapshots of updated data in the Chrome console.

Complete Code:

import { Component, effect, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

// Include Order and OrderItem classes...
// Set up hard-coded initial Order...

@Component({
  selector: 'app-root',
  template: `
    <a target="_blank" href="https://angular.dev/overview">
      Learn more about Angular
    </a>
  `,
})
export class App {
  PackingOrder = signal<Order>(hardCodedOrder);

  constructor() {
    effect(() => {
      console.log('order changed', structuredClone(this.PackingOrder()));
    });
  }

  ngOnInit() {
    setTimeout(() => {
      this.PackingOrder.update((order: Order) => {
        const foundItem = order.orderItems.find(
          (item: OrderItem) => item.packed === 2
        );
        if (foundItem) {
          foundItem.unitQty = 10000;
          // If updated, trigger a signal change via object destructuring.
          return order.clone();
        }
        return order;
      });
    }, 5000);
  }
}

bootstrapApplication(App);

View Stackblitz Demo

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

Accessing an HTML file in a web browser through Eclipse

Whenever I try to open my HTML document by right-clicking and selecting "open with web browser", the browser opens but doesn't show any content. The strange thing is, other HTML documents in my different projects work perfectly fine. Any ideas on why ...

Utilizing jQuery's .slidedown alongside Prototype's .PeriodicalUpdater: A Comprehensive Guide

I am currently working on creating an activity stream that automatically updates with the latest entries from a database table every time a new row is added. Right now, I am using Prototype's Ajax.PeriodicalUpdater to continuously check for new entri ...

Can you explain the significance of these specific HTML attributes within the button tag?

While browsing the web, I stumbled upon this HTML snippet: <button class="button--standard" mat-button mat-flat-button [disabled]=true >Disabled State</button> The combination of attributes like mat-button mat-flat-button [disabled]=true is u ...

Mastering the art of implementing async/await properly within token validation scenarios

I am currently working on setting up an Express.js backend for a website that authenticates users using Google Sign-in. My goal is to develop a RESTful API call that: Accepts an ID token. Authenticates the token using Google's OAuth2 Library. Veri ...

Struggling to dynamically fill the table with Ajax Json data

After retrieving data from my webservice call, I am sending this JSON response: [ [ { "id": 123, "vendorName": "PoppyCounter", "item": "Chocolate" }, { "id": 1234, "ve ...

Unable to retrieve mongoose Schema context while using Typescript

I am attempting to use the functions .pre, .method, and .static with my Mongoose Schemas. The code I have written seems to be causing issues, as my understanding of Schemas or the context of this may be incorrect. export interface IUser extends mongoose. ...

Content OverFlow: DropDown Menu is not overlapping the content, but rather pushing it downwards

In my webpage, I have a drop-down menu that traditionally pushes the content below it down to make space for its items. However, I want the drop-down to overlap the contents below without affecting their position. I've tried various solutions, such a ...

"An error has occurred: React's this.setState function cannot

This draft of the Typehead class is still a work in progress, with the final version intended to display a list of choices from props that match the user input, essentially functioning as an autocomplete feature. I am encountering an error message "cannot ...

The shop named 'someStore' is currently unavailable! Please ensure that it is being offered by a valid Provider

I'm having trouble setting up a new project using React, Typescript, and MobX. Despite having a relatively simple piece of code, I can't seem to get MobX to work properly. It keeps showing me this error message: Uncaught Error: MobX injector: S ...

Manipulate Attributes in Javascript

Having an issue here - I'm trying to use JavaScript to set some attributes. for(i=0;i<div_navi.childNodes.length;i++){ if(div_navi.childNodes[i].nodeName =="SPAN"){ div_navi.childNodes[i].setAttribute("onclick","g ...

Unauthorized Access with Ajax jQuery

While working on an ajax request using Jquery, I encountered a dilemma. Even though the page is only accessible to logged in users, my cookies are not being sent along with the request. This results in a 401 error. I am already logged in, so why aren' ...

Effortless sliding panel that appears on hover and vanishes when mouse is moved away

I am in the process of creating a menu for my website that utilizes linkbuttons which trigger additional linkbuttons to slide down upon hover. The desired effect is a smooth sliding panel that appears when hovering over the linkbutton, and disappears when ...

Modify the div's visibility based on selected option in the dropdown menu

In my PHP file, I have the following codes: <section id="placeOrder"> <h2>Place order</h2> Your details Customer Type: <select name="customerType"> <option value="">Customer Type?</option> <option value="ret ...

Add a new row to the table when a dropdown option is selected, and remove the row when deleted. Ensure that the row is only added

Here is my specific requirement: I need a table with a default row containing a dropdown menu in the first column. When an option is selected from the dropdown, a new table row should be added with the same content as the main row and a delete button for ...

Is there a way to verify the presence of a service worker on a specific URL?

Is there a way for me to determine if external websites have a 'service-worker' or not? Here is what I think could work: Extract all the JavaScript files from the given URL Look for the string 'sw.js' (I am not entirely sure how to ...

Having trouble with webpack-dev-server causing a blank screen when trying to hot reload Electron app with Angular version 1

Currently, I am diving into Electron and experimenting with building a simple app in Angular using webpack for livereload. However, I have encountered an issue where on hot reload, the app displays a blank view (*see screenshot below) and I have to restart ...

Struggle with comparing strings in different cases

When utilizing the "WithText" function within a Testcafe script, it appears to be case-sensitive. How can I modify it to be case-insensitive? For example, allowing both "Myname" and "myname" for a user input. It's problematic when a script fails due t ...

Refresh the page with cleared cache using window.location.reload

Is there a way to reload a page using JavaScript and still clear the cache, ensuring that the refreshed page shows the latest content from the server? It seems that other browsers are not displaying the most up-to-date versions of the content. Anyone have ...

Issues with Angular routes containing URL parameters arise when deploying on Google App Engine or AWS S3, while functioning flawlessly on localhost or local IP addresses

Recently, I completed my first full-fledged application using Angular and deployed it on both Google App Engine and AWS Free Tier. The backend is powered by a Spring Boot Rest API deployed on AWS. The application loads perfectly fine with the root domain ...

Is it possible for a method within a variable in Typescript to invoke another method?

I need to execute a random function in my code. Here is what I have: module A { ... export function foo(): number { let b = new B(); let possibleFunctions = [ b.possibleFunction1, b.possibleFunction2 ...