因多次零钱扣除而导致总价值错误如何防止?

Getting wrong total value because of multiple change deduction how to prevent?

我得到了错误的值,因为扣除了多次零钱。如何预防?

app.component.ts :

import { Component, OnInit } from "@angular/core";

interface PropsData {
  productName: string;
  value: number;
  count: number;
  details: (value1: number, value2: number) => number;
}

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  products: PropsData[];
  allTotal: number = 0;

  ngOnInit() {
    this.products = [
      {
        productName: "sugar",
        value: 20,
        count: 1,
        details: (value1, value2) => {
          return this.grandTotal(value1, value2);
        }
      },
      {
        productName: "salt",
        value: 40,
        count: 1,
        details: (value1, value2) => {
          return this.grandTotal(value1, value2);
        }
      },
      {
        productName: "jackery",
        value: 70,
        count: 1,
        details: (value1, value2) => {
          return this.grandTotal(value1, value2);
        }
      }
    ];
  }

  updateCount(product: PropsData) {
    product.count++;
  }

  updateAllTotal(itemTotal: number): void {
    this.allTotal = this.allTotal + itemTotal;
  }

  grandTotal(value1, value2): number {
    const total = value1 * value2;
    this.updateAllTotal(total);
    return total;
  }
}

html:

<div>
  <div *ngFor="let product of products">
    <h1>{{product.productName}}</h1>
    <p>{{product.count}}</p>
    <p>Total: {{product.details(product.count, product.value)}}</p>
    <p><button (click)="updateCount(product)">Add Product</button></p>
  </div>
  <h2>Grand Total: {{allTotal}}</h2>
</div>

Live Demo

作为一般规则,应使用绑定到方法 :在您的情况下,我将重构代码以避免绑定到 product.details()

第一个解决方案

一个简单的方法是在更新时声明一个事件发射器通知product.countproduct.details可以变成一个简单的属性(而不是一个方法)并且在事件处理程序中更新。

    interface PropsData {
      productName: string;
      value: number;
      count: number;
      details: number;
    }

您的组件可能如下所示:

products: PropsData[];
  allTotal: number = 0;
  onProductUpdate = new EventEmitter<PropsData>();

  ngOnInit() {
    this.products = [
      {
        productName: "sugar",
        value: 20,
        count: 1,
        details: 20 // Needs to be manually initialized, as it's not a function anymore
      },
      {
        productName: "salt",
        value: 40,
        count: 1,
        details: 40
      },
      {
        productName: "jackery",
        value: 70,
        count: 1,
        details: 70
      }
    ];

    this.updateAllTotal(); // Compute allTotal the first time
    
    // On every product update compute product.details and allTotal
    this.onProductUpdate.subscribe((product) => {
      product.details = this.getProductDetails(product);
      this.updateAllTotal();
    });
  }

  updateCount(product: PropsData) {
    product.count++;
    this.onProductUpdate.next(product);
  }

  updateAllTotal(): void {
    this.allTotal = 0;
    this.products.forEach(
      (item) => (this.allTotal = this.allTotal + item.details)
    );
  }

  getProductDetails(product): number {
    return product.count * product.value;
  }

现在这可能是您的模板(不再有函数绑定):

<div>
  <div *ngFor="let product of products">
    <h1>{{product.productName}}</h1>
    <p>{{product.count}}</p>
    <p>Total: {{product.details}}</p>
    <p><button (click)="updateCount(product)">Add Product</button></p>
  </div>
  <h2>Grand Total: {{allTotal}}</h2>
</div>

CodeSandbox

备选方案

根据您的实际用例的复杂程度,另一种方法是在产品本身中封装每次 valuecount 更改时更新其详细信息的逻辑。为此,您需要将 PropsData 更改为 class:

class PropsData {
  productName: string;
  private _value: number;
  private _count: number;
  public get value() {
    return this._value;
  }
  public set value(value) {
    this._value = value;
    this.details = this._value * this._count;
  }
  public get count() {
    return this._count;
  }
  public set count(value) {
    this._count = value;
    this.details = this._value * this._count;
  }
  details: number;

  constructor(name: string, value: number, count: number) {
    this.productName = name;
    this.count = count;
    this.value = value;
  }
}

如您所见,valuecount setter 也负责更新 details。这简化了组件的逻辑:

products: PropsData[];
  allTotal: number = 0;

  ngOnInit() {
    this.products = [
      new PropsData("sugar", 20, 1),
      new PropsData("salt", 40, 1),
      new PropsData("jackery", 70, 1)
    ];
    this.updateAllTotal();
  }

  updateCount(product: PropsData) {
    product.count++;
    this.updateAllTotal();
  }

  updateAllTotal(): void {
    this.allTotal = 0;
    this.products.forEach(
      (item) => (this.allTotal = this.allTotal + item.details)
    );
  }

CodeSandbox