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

How can I incorporate the LIKE operator in a query when dealing with PostgreSQL's String array type using TypeORM?

My database backend is PostgreSQL and I have a TypeORM object simplified as follows: @Entity() @Index(['name'], {unique: true}) export class Foo extends BaseEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column() name: st ...

Issue with clearTimeout function not functioning properly on keyup event in iFrame

While there may be many similar questions out there, I have yet to find a solution that works for me. Currently, I am developing a WYSIWYG editor and I want it to save when the user performs a keyup action. However, I do not want it to update after every ...

What is the best way to showcase column data in a React table when the data within the column is an array of objects?

Utilizing a react table to showcase a data table. In the tags column, the goal is to display all tags present in the tags array of objects. Despite several attempts, no success has been achieved yet. Being new to working with tables, any guidance on a more ...

Error NG0303: Unable to connect to X because it is not recognized as a property of Y

Recently, I made the switch to Angular 17 in my application The error I'm encountering seems to only occur when running the test command ng test Everything works fine with building and executing the application, it has been deployed to production wi ...

Determining Checkbox State in Angular 2: A Simple Guide

I have a set of checkboxes displayed like this: moduleList = ['test1', 'test2', 'test3', 'test4'] <li *ngFor="let module of moduleList"> <input [value]="module" type="checkbox"> {{module}}<br> < ...

What are some reasons why the XMLHttpRequest ProgressEvent.lengthComputable property could return a value of

I've been struggling to implement an upload progress bar using the XMLHttpRequest level 2 support for progress events in HTML5. Most examples I come across show adding an event listener to the progress event like this: req.addEventListener("progress ...

The promise of returning a number is not compatible with a standalone number

I am currently working on a function that retrieves a number from a promise. The function getActualId is called from chrome.local.storage and returns a promise: function getActualId(){ return new Promise(function (resolve) { chrome.storage.syn ...

Localizing your Angular 2 application with multiple languages

I'm currently working on localizing my Angular 2 app based on the browser's language settings. I send a POST request to my database to retrieve translations for the specified language in the header. Current Implementation: I have a shared varia ...

Disabling the intellisense feature for locale suggestions in Monaco is recommended

Switch the keyboard language to a different one (in this case Japanese using alt + shift), and when typing in Monaco editor, an intellisense menu appears with options to remove and search. Monaco Editor Version: V0.33.0 https://i.stack.imgur.com/SIyeV.pn ...

Discovering the absent number within a cyclical array

Looking to find the missing number between two arrays in a cyclical manner using either Javascript or jQuery. It's easy to find all missing numbers, but I specifically need to identify the single missing number within the range of the second array whi ...

How can you center popup windows launched from the main window using jquery?

Within my web application, I frequently utilize popup windows that open at different locations on the screen. These popups are standard windows created with window.open() rather than using Jquery. Now, I am seeking a solution to automatically center all p ...

Contrast the differences between arrays and inserting data into specific index positions

In this scenario, I have two arrays structured as follows: arr1=[{room_no:1,bed_no:'1A'}, {room_no:1,bed_no:'1B'}, {room_no:2,bed_no:'2A'}, {room_no:3,bed_no:'3A'}, {room_no:3,bed_no:'3B ...

Tips for displaying the data on top of individual column bars: Hightcharts, Vue-chartkick, and Cube Js

Looking for assistance with adding value labels to the top of each column bar in a Vue chart using chartkick and highcharts. https://i.sstatic.net/c4Bwc.jpg Check out the image above to see my current output. <template> <column-chart lable= ...

Button inside a React JS Material UI autocomplete chips component

The image above showcases two input fields with autocomplete functionality. The first field effectively uses chips for autocomplete suggestions. However, the second field features an autocomplete but is non-functional, with a button inserted inside the Tex ...

JSON Serialization Results Include a Property for Counting

In my C# project, I'm facing an issue with serializing an array of objects into JSON. The type of array I'm dealing with is Object[], not Array<Object>. Currently, the serialization process is handled automatically by a JsonMediaTypeFormatt ...

What steps are needed to troubleshoot and resolve issues with integrating Google reCaptcha in an AWS Lambda

I'm encountering an issue with my lambda function which is intended to validate google recaptcha. Despite sending the correct data (the response) from the client, I consistently receive a console message stating "verification failed". Below is the cod ...

Storing data from PHP in Local Storage using JavaScript variable

When a specific build name is clicked, the inner HTML content is captured and assigned to a JavaScript variable called loadDump. This variable is then sent over to PHP via an AJAX request. $.ajax({ url:"http://custom-assembly.tcad.co.uk/wp-content/t ...

How to display a PDF in a new tab using Angular 4 and a Node API

I have a specific requirement to generate a PDF view of my Angular 4 app's UI using a Node.js API. To achieve this, I extracted the entire content from the UI and conducted some pre-processing before sending it to the Node.js API. Within the Node API, ...

A single snippet of JavaScript blocking the loading of another script

I've encountered an issue where the code seems to be conflicting with itself. The top part works fine, but the bottom part doesn't. However, when I remove the top portion, everything works as intended! You can see a working example of both compo ...

Strategies for enhancing performance in an Angular 4 project

Currently, I am engaged in a project that involves utilizing Angular 4 for the front-end and PHP for the back-end with the support of an Apache server on Ubuntu 16.04 LTS. We have incorporated Node JS to facilitate the functionality of Angular. This raises ...