Discovering identical objects in two arrays in Angular using TypeScript is a breeze

I've hit a roadblock with a TypeScript problem in my Angular service. I have an array of ingredients:

private ingredients: Ingredient[] = [
  new Ingredient('farina', 500),
  new Ingredient('burro', 80),
  new Ingredient('uccellini', 5)
];

This is the model:

export class Ingredient {constructor(public name: string, public amount: number){}}

I want to add new ingredients to the array and trigger an event with a copy of the updated array. This method works:

newIngredients = [
  new Ingredient('mais', 100),
  new Ingredient('uccellini', 5)
];

addIngredients(newIngredients: Ingredient[]) {
  this.ingredients.push(...ingredients);
  this.ingredientsChanged.emit(this.ingredients.slice());
}

However, I now aim to check if a new ingredient object already exists in the ingredients array. If it does, I need to combine the amounts and update the existing object before pushing it back into the array and returning a copy.

Desired output:

[
  new Ingredient('farina', 500),
  new Ingredient('burro', 80),
  new Ingredient('uccellini', 10)
  new Ingredient('mais', 100)
];

I've experimented with Set, WeakSet, Map, and other approaches, but my limited knowledge of TypeScript has me stuck at this point:

addIngredients(newIngredients: Ingredient[]) {

  let hash = {};
  this.ingredients.forEach(function (ingr) {
    hash[ingr.name] = ingr;
  });

let result = newIngredients.filter(function (ingr) {
  if (!(ingr.name in hash)) {
    return !(ingr.name in hash);
  } else {
    // ???
  }
});

  this.ingredients.push(...result);
  this.ingredientsChanged.emit(this.ingredients.slice());
}

Any assistance would be greatly appreciated. Thank you!

Answer №1

Consider a scenario where you have two different arrays of ingredients:

const initialIngredients: Ingredient[] = [
  new Ingredient('flour', 500),
  new Ingredient('butter', 80),
  new Ingredient('eggs', 5)
];

and

const newIngredients = [
  new Ingredient('corn', 100),
  new Ingredient('eggs', 5)
];

If your goal is to merge these arrays by adding any new ingredients and combining existing ones, a possible approach would be to merge both arrays and then use the reduce method to create a single combined list.

const combinedList = initialIngredients
  .concat(newIngredients)
  .reduce((previous: any[], current: any) => {
    const matchingIngredient = previous.filter(i => i.name === current.name);
    if (matchingIngredient.length > 0) {
      previous.push({ ...current, value: matchingIngredient.shift().value + current.value });
    } else {
      previous.push(current);
    }
    return previous;
  }, []);

Answer №2

Latest update:

  1. The 'this.ingredients' property is not accessible within the forEach loop due to a change in context

  2. To overcome this, the current scope is assigned to a new variable 'that', allowing access to 'that.ingredients' inside the loop

Explore the code on StackBlitz: https://stackblitz.com/edit/angular-fulrcg

addIngredients(newIngredients: Ingredient[]) {

    let exist: boolean = false;
    let that = this;
    //debugger;
    console.log(this.ingredients);
    newIngredients.forEach(function(newIngr, newKey) {
      exist = false;
      console.log(newIngr);
      that.ingredients.forEach(function (ingr, key) {
        if(ingr["name"] == newIngr["name"]) {
          ingr["amount"] += newIngr["amount"];
          exist = true;
        }
      });
      if(!exist) {
        **that.ingredients**.push(newIngr);
      }
    });

Answer №3

Here is the code snippet provided for reference:

Sample Stackblitz URL: https://stackblitz.com/edit/angular-uf4dcr

Main Component HTML File - app.component.html

<button (click)="add()">Add</button>

<ul>
  <li *ngFor="let ing of ingredients">
    {{ing.name}} - {{ing.amount}}
  </li>
</ul>

Main Component TypeScript File - app.component.ts

import { Component } from '@angular/core';

class Ingredient {
  constructor(public name: string, public amount: number){ }
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';

  private ingredients: Ingredient[] = [
    new Ingredient('farina', 500),
    new Ingredient('burro', 80),
    new Ingredient('uccellini', 5)
  ];

  addIngredients(newIngredients: Ingredient) {

    let exist: boolean = false;
    this.ingredients.forEach(function (ingr) {
      if(ingr["name"] == newIngredients["name"]) {
        ingr["amount"] += newIngredients["amount"];
        exist = true;
      }
    });

    if(!exist) {
      this.ingredients.push(newIngredients);
    }

      //this.ingredientsChanged.emit(this.ingredients.slice());
      console.log([...this.ingredients]); //return copy of the updated array
  }

  add() {
    this.addIngredients({name: 'farina', amount:10});
    this.addIngredients({name: 'new item', amount:100});
  }

}

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

Using `preventDefault()` does not stop the action from occurring

Whenever I apply event.preventDefault() to a link, it works perfectly fine. But when I do the same for a button, it doesn't seem to have any effect! Check out the DEMO This is the code snippet in question: <a id="link" href="http://www.google.co ...

Operating a React application in the background

Being a novice in the world of deploying front-end code, I have encountered a challenging situation that requires assistance. I am currently working on a React App that needs to be operated as a background process. However, I'm facing some confusion r ...

Typescript input event

I need help implementing an on change event when a file is selected from an input(file) element. What I want is for the event to set a textbox to display the name of the selected file. Unfortunately, I haven't been able to find a clear example or figu ...

Angular version 4 is used to retrieve deeply nested JSON data

How do I extract data from a nested JSON file? Here is an example of the JSON structure: { "user1": { "name": "john", "surname": "johnsson" }, "user2": { "name": "Jacob", "surname": "Jacobsson" } } I want t ...

Which is the preferred method: utilizing ajax calls from assets/javascript/*.js or *.js.erb views?

I am developing an admin service on Rails that communicates with a network communicator. Here is my challenge: When a user clicks a button, they are presented with network groups to choose from. Once the user selects a group, they should be able to see th ...

My navigation menu has a nested ul, but on mobile devices, it doesn't display all the items in the list. What could be causing

When I click on "Products" in my main navigation, only the first 6 items are displayed from a nested ul. How can I make all of them display when the user clicks on "Products"? Is this a CSS issue or a problem with the script? Here's a screenshot for r ...

"When testing with an API client, NextJS 13 successfully returns a response, however, the same response

Having trouble getting a clear answer on something really simple. I've created an API route: // /api/test/route.js export async function GET(request, response) { console.log("requested"); return NextResponse.json({ my: "data" ...

I possess information stored within the array object below, and I aim to transform it into a different array object format

Here is the response I received from my API: let data = [ { date: '2021-04-27', formatted_date: 'Apr 27', location: [ { date: '2021-04-27', formatted_date: 'Apr 27', countr ...

Is there a way to retrieve the number of swipe up interactions from Instagram story insights using the graph API

Is there a way to retrieve the swipe up count displayed in Instagram insights? Since Facebook does not provide this data through their Graph API, how can I access it? I have already tried scraping without success and I am looking for a solution using eith ...

Tips for choosing the remaining items in a multiple selection process

In my HTML form, I have a multi-select field that contains categories and the corresponding items within each category. My goal is to allow users to select individual courses or select an entire category (identified by values starting with "cat_") in orde ...

Is there a way to access hover effect information in Atom editor similar to how it appears in VScode?

Is there a specific plugin required in Atom to display information when hovering over variables, objects, or functions similar to intellisense? VSCode does this automatically, but I am looking for the same functionality in Atom. https://i.stack.imgur.com/ ...

Experiencing difficulties with managing immutable state within ngrx framework

Hi there, I'm currently exploring ngrx and trying to implement immutable state management. However, I've run into some issues with getting it to work properly. Below is the reducer I am working with: https://stackblitz.com/edit/brewbrut?file=src ...

Typescript: Declaring object properties with interfaces

Looking for a solution to create the childTitle property in fooDetail interface by combining two properties from fooParent interface. export interface fooParent { appId: string, appName: string } export interface fooDetail { childTitle: fooParent. ...

The android webview is having trouble loading HTML that includes javascript

I have been attempting to showcase a webpage containing HTML and JavaScript in an android webview using the code below. Unfortunately, it doesn't seem to be functioning properly. Can someone provide assistance? Here is the code snippet: public class ...

An array of objects can be used as input for the autocompleteItems in ngx-chips

Recently, I've been exploring the use of Angular 4 ngx-chips for input tags and came across an interesting issue. While looking at the documentation on ngx-chips, I noticed a problem with using an array of objects as input for 'autocompleteitems& ...

Having trouble installing the @mui/x-data-grid package in a React project

npm install @mui/x-data-grid encounters a problem that throws an error message: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" dat ...

Every time I try to restart my React Project, it seems to encounter strange issues that

Currently, I am following a fullstack React tutorial which you can find here: React Tutorial I have encountered an issue where every time I close my laptop and reopen the project, npm start throws a strange error. Initially, I tried to fix it by starting ...

Is it possible to change between universal and spa mode based on the query string?

Currently, I am working on a Nuxt.js application set to universal mode and deployed as a static website using nuxt generate. The app is pulling data from a GraphQL API linked to a CMS, and everything is functioning properly. Whenever content is updated in ...

The functionality to disable the ES lint max length rule is malfunctioning

In trying to disable an eslint rule in a TypeScript file, I encountered an issue with a regular expression that exceeded 500 characters. As a result, an eslint warning was generated. To address this, I attempted to add an eslint comment before declaring th ...

Has the GridToolbarExport functionality in Material UI stopped working since the latest version update to 5.0.0-alpha.37?

I have created a custom toolbar for my Data Grid with the following layout: return ( <GridToolbarContainer> <GridToolbarColumnsButton /> <GridToolbarFilterButton /> <GridToolbarDensitySelector /> <Gr ...