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-total
和 app-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()` 链来分别在父子之间进行通信..
我有 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-total
和 app-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()` 链来分别在父子之间进行通信..