I have 3 components (Sales, ProductSales, ProductTotals) that share an array of products but the ProductsTotal component is not reading the changes of the array. The father component (Sales) initializes the array of products and set as intnput for the child components, the ProductSales component changes the value of the array of products (add, remove, change properties like unit price, etc) and the ProductTotals component read the array and constantly does the operations to obtain the total of the sum of the unit prices of the products and displays them.
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>
To display the totals i did this 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;
}
}
The problem is that only enters the ngOnChanges method once even though the object of products is changing.
The result of updating products in ProductsSalesComponent:
Edit I've created a project in StackBlitz to show the problem about how the ngOnChange event of the component 'ProductSaleTotal' is not fire when the object 'products' changes https://stackblitz.com/edit/angular-fcevey?file=src%2Fapp%2Fproducts-sale-total%2Fproducts-sale-total.component.ts
app-products-sale-total
and app-products-sale
are both different component, so to communicate with them you need to use @Output()
from app-products-sale
and pass array of object to app-products-sale-total
... Complete working example you can find out here in this StackBlitz Link
Your ProductSaleDetailComponent.ts
is...
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});
}
}
Your ProductsSaleComponent template is...
<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>
Your ProductSaleComponent.ts is...
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);
}
}
So, basically you need chain of @Input() and
@Output()` to communicate between child-parent respectively..