Angular 2+ 当组件间的共享对象改变时捕捉事件

Angular 2+ Catch event when shared object between components changes

我有 3 个组件(Sales、ProductSales、ProductTotals)共享一个产品数组,但 ProductsTotal 组件没有读取数组的变化。父组件(Sales)初始化产品数组并设置为子组件的 intnput,ProductSales 组件更改产品数组的值(添加、删除、更改单价等属性),ProductTotals 组件读取数组,不断运算得到商品单价总和并显示。

SalesComponent.html

<app-products-sale-total class="full-wid" [products]="products"></app-products-sale-total>
<app-products-sale class="full-wid" [products]="products"></app-products-sale>

为了显示总数,我这样做了 ProductTotals.html

{{products.length}}
<strong>Taxes:</strong> {{taxes|currency}} 
<strong>Subtotal:</strong> {{subtotal|currency}} 
<strong>Total:</strong> {{total|currency}} 

ProductsTotal.ts

import { Component, OnInit, Input, OnChanges, OnDestroy, SimpleChange } from '@angular/core';
import { ProductSale } from '../product-sale-detail/product-sale-detail.component';

@Component({
  selector: 'app-products-sale-total',
  templateUrl: './products-sale-total.component.html',
  styleUrls: ['./products-sale-total.component.scss']
})
export class ProductsSaleTotalComponent implements OnChanges {

  @Input() products: Array<ProductSale> = [];
  total: number = 0;
  subtotal: number = 0;
  taxes: number = 0;
  constructor() {
   }

  ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
    calculateTotalFields();
    console.log(changes);
  }

  calculateTotalFields(): void {
    let total = 0;
    let subtotal = 0;
    let taxes = 0;
    this.products.forEach(x => {
      const totalProduct = x.UnitPrice * x.Quantity;
      const taxesProduct = totalProduct * 0.16;
      total += totalProduct;
      subtotal += totalProduct - taxesProduct;
      taxes += taxesProduct;
    });
    this.total = total;
    this.taxes = taxes;
    this.subtotal = subtotal;
  }
}

问题是即使products的对象在变化,也只进入ngOnChanges方法一次。

在 ProductsSalesComponent 中更新产品的结果:

编辑 我在 StackBlitz 中创建了一个项目来展示组件 'ProductSaleTotal' 的 ngOnChange 事件在对象 'products' 更改时如何不触发的问题 https://stackblitz.com/edit/angular-fcevey?file=src%2Fapp%2Fproducts-sale-total%2Fproducts-sale-total.component.ts

app-products-sale-totalapp-products-sale 都是不同的组件,因此要与它们通信,您需要使用 app-products-sale 中的 @Output() 并将对象数组传递给 app-products-sale-total...您可以在此处找到完整的工作示例 StackBlitz Link

你的ProductSaleDetailComponent.ts是...

export class ProductSaleDetailComponent implements OnInit {
    @Input() product: ProductSale;
    @Input () index: number;
    @Output() productData = new EventEmitter();
    constructor() { }

    ngOnInit() {
       this.product.Quantity = 1;
    }

    changeInput(p){
        this.productData.emit({event: 'add',value:p, index : this.index});
    }
}

您的 ProductsSaleComponent 模板 是...

    <button type="button" (click)="addProduct()">Add Product!</button>
        <div *ngFor="let product of products; let i=index">
             <div> 
                 <app-product-sale-detail [product]="product" [index]="i" (productData)= "productOutput($event)" ></app-product-sale-detail>
             </div>
        <div>
            <button aria-label="Delete" color="warn" (click)="removeProduct(i)">
              Remove Product
            </button>
        </div>
    </div>

你的ProductSaleComponent.ts是...

export class ProductsSaleComponent implements OnInit {

   @Input() products: Array<ProductSale> = [];
   @Output() ProductOutputData = new EventEmitter(); 
   constructor() { }

   ngOnInit() {
      console.log('product Sale',new ProductSale());
   }

   addProduct() {
      this.products.push(new ProductSale());
   }

   removeProduct(index: number) {
      this.ProductOutputData.emit({event:'remove', index: index, value : this.products[index]} );
      this.products.splice(index, 1);
   }
   productOutput(event){
      this.ProductOutputData.emit(event);
   }
}

所以,基本上你需要 @Input() and@Output()` 链来分别在父子之间进行通信..