.push() an Object into an Array updates other similar objects in the Array

Quite a strange problem:

In my DOM I generate a list that is clickable. On click a function is called with the clicked object as an argument and this said object is then attributed an ID and pushed into an array. Problem is that all similar objects get their IDs and any other value updated too. Meaning that if I click on Object1 two times, both objects in the array will get updated.

DOM:

<div class="col-3" *ngFor="let product of consolidatedProducts" (click)="selectProduct(product)">
  <div class="productSearchCard">
    <div class="name">
      {{product.name}}
    </div>
    <div class="price">
      {{product.price}} {{product.currency}} 
      <span *ngIf="product.unit">
        {{product.unit.short}}
      </span>
    </div>
    <div class="description">
      {{product.description}}
    </div>                                    
  </div>
</div>

Component

public selectProduct(product: any) {
  const id = new Date().getTime();
  product.id = id;
  this.selectedProducts.push({
    id,
    component: product
  });
}

After the push happens, all object in the array have the same ID in the product even if the id is different in the object id. See output below:

[
  0: {
    component: {
      id: 1573220848440
      name: "Set of sticker"
      price: "9"
      quantity: "1"
      sub-category: "Sticker"
      unit: {long: "piece", short: "p."}
    },
    id: 1573220848274
  },
  1: {
    component: {
      id: 1573220848440
      name: "Set of sticker Swiss Realty"
      price: "9"
      quantity: "1"
      sub-category: "Sticker"
      unit: {long: "piece", short: "p."}
    },
    id: 1573220848440
  }
]

Replicated here: https://stackblitz.com/edit/angular-1bhaqn

2 answers

  • answered 2019-11-08 14:19 Jason White

    The problem is you're always referencing the same object in memory when you run selectProduct(product). You need to make a deep copy of the object before assigning the new values to it, then push the new object to the array.

    public selectProduct(product: any) {
        // MAKE DEEP COPY OF OBJECT (THERE ARE OTHER WAYS TO DO THIS ALSO)
        const newProduct = JSON.parse(JSON.stringify(product));
        const id = new Date().getTime();
        newProduct.id = id;
        this.selectedProducts.push({
          id,
          component: newProduct
        });
        console.log(this.selectedProducts);
      }
    

    https://stackblitz.com/edit/angular-rjxor4

  • answered 2019-11-08 14:20 maurycy

    If you can use spread operators I'd suggest doing something like this to make a copy fo object and push it as new

      public selectProduct(product: any) {
        const id = new Date().getTime();
        const newProduct = {
          ...product,
          id
        }
        this.selectedProducts.push({
          id,
          component: newProduct
        });
        console.log(this.selectedProducts);
      }