函数应修改新数组时,对象的原始角度数组已修改

时间:2019-12-04 19:23:27

标签: javascript angular typescript

我有一系列导入到add-product.component.ts的产品

有一项功能,您可以将产品添加到称为购物篮的购物车中

car.service将要执行的操作是将产品添加到名为basketItems的数组中。如果产品已经存在于basketItems数组中,则它应更改basketItem的该条目。

由于某种原因,购物篮和产品都在变化,这导致原产地商品的价格在只有购物篮的情况下才会发生变化。

我是Angular的新手,我不确定我在add-product.component.html.p

中运行(click)=“ addToCart(product)”时是否传递了该产品的引用

Product Page before adding anything to the cart

Product Page after adding something to the cart

add-product.component.html

产品系列

<div class="d-flex justify-content-between flex-wrap">
    <div *ngFor='let product of products' class="card mb-5" style="width: 20rem; height: 20rem">
        <img style="object-fit: contain; margin-top: 5%" height="45%" src={{product.image}} [title]='product.name' class="card-img-top" alt={{product.name}}>
        <div class="card-body">
            <div class="mb-3">
                <h5 class="card-title">{{product.name}}</h5>
                <p class="card-text">{{product.description | slice:0:60}}...</p>
            </div>
            <a style="float: left" (click)="addToCart(product)" class="card-link text-primary">Add</a>
            <p style="float: right">{{product.price | currency}}</p>
        </div>
    </div>
</div>
<div>
    <div>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th scope="col"></th>
                    <th scope="col">Count</th>
                    <th scope="col">Product Name</th>
                    <th scope="col">Description</th>
                    <th scope="col">Price</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor='let item of basket; index as itemId'>
                    <th scope="row"><button (click)="removeFromCart(itemId)">X</button></th>
                    <th scope="row">{{item.count}}</th>
                    <td>{{item.name}}</td>
                    <td>{{item.description | slice:0:20}}</td>
                    <td>{{item.price | currency}}</td>
                </tr>
            </tbody>
            <thead>
                <tr>
                    <th colspan="3" scope="col"></th>
                    <th scope="col">Total:</th>
                    <th scope="col">{{total | currency}}</th>
                </tr>
            </thead>
        </table>
    </div>
    <button style="float: right" class="btn btn-primary">CHECK OUT</button>
</div>

add-product.component.ts

import { Component, OnInit } from "@angular/core";
import { products } from "../products";
import { CartService } from "../cart.service";

@Component({
  selector: "app-add-product",
  templateUrl: "./add-product.component.html",
  styleUrls: ["./add-product.component.css"]
})
export class AddProductComponent implements OnInit {
  // Array of products to be displayed on screen for the user to add to the basket
  products: object[] = products;

  // The basket is an array of items that were added by the user when they click the add button for that product
  basket: object[];
  total: number;
  constructor(private cartService: CartService) {}

  addToCart(item) {
    this.cartService.addToCart(item);
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  removeFromCart(index) {
    this.cartService.removeFromCart(index);
    this.basket = this.cartService.getItems();
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  ngOnInit() {
    this.basket = this.cartService.getItems();
  }
}

cart.service.ts

import { Injectable } from "@angular/core";
import { AngularFirestore } from "@angular/fire/firestore";
@Injectable()
export class CartService {
  basketItems: object[] = [];

  constructor(private db: AngularFirestore) {}

  addToCart(product) {
    // if product is already in the basket
    // FIX ME basket should mutate and not the product
    for (let i = 0; i < this.basketItems.length; i++) {
      if (product === this.basketItems[i]) {
        let originalPrice =
          this.basketItems[i].price / this.basketItems[i].count;
        this.basketItems[i].count = this.basketItems[i].count + 1;
        this.basketItems[i].price = this.basketItems[i].price + originalPrice;
        console.log("this should not mutate ===>", product, "but it does");
        return;
      }
    }

    this.basketItems.push(product);
  }

  removeFromCart(index) {
    this.basketItems.splice(index, 1);
  }

  getItems() {
    return this.basketItems;
  }

  clearCart() {
    this.basketItems = [];
    return this.basketItems;
  }
}


已更新,以提高准确性

1 个答案:

答案 0 :(得分:0)

这将返回一个引用:

 getItems() {
    return this.items;
    console.log(this.items);
  }

然后您将其分配给您的购物篮:

ngOnInit() {
    this.basket = this.cartService.getItems();
  }

因此它们都指向相同的参考。当您对购物车服务项目进行更改时,您还需要修改购物篮。

如果您想避免这种行为,可以使用这样的方式

getItems() {
    return this.items.slice(0); // or [...this.items] a.k.a create a new instance every time
    console.log(this.items);
}

然后进行编辑:

if (product === this.basketItems[i]) { // you check exactly they have same reference
   let originalPrice =
   this.basketItems[i].price / this.basketItems[i].count;
   this.basketItems[i].count = this.basketItems[i].count + 1;
   this.basketItems[i].price = this.basketItems[i].price + originalPrice;
        console.log("this should not mutate ===>", product, "but it does");

因此,如何修改引用并不重要。他们都被修改了。

因此,您正在往返跳动相同的对象。 您需要做的是:

 this.basketItems.push({...product}); // insert new object everytime
 // and checking part should be
 if (product.id === this.basketItems[i].id) // they are not same object anymore you can not check reference equality.