I am getting wrong 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>
CodePudding user response:
As a general rule binding to a method should be used sparingly: in your case I would refactor the code in order to avoid the binding to product.details()
.
First solution
A simple way to do that is to declare an event emitter notifying when you're updating product.count
: product.details
could become a simple property (instead of a method) and gets updated in the event handler.
interface PropsData {
productName: string;
value: number;
count: number;
details: number;
}
This is how your component might look like:
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;
}
And this could be your template now (no function binding anymore):
<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>
Alternative solution
Depending on how complex your real use case is, a different approach would be to encapsulate in the product itself the logic for updating its details every time value
or count
changes. For this you need to change PropsData
to a 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;
}
}
As you can see, value
and count
setters take care of updating details
as well. This simplifies the component's logic:
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)
);
}
CodePudding user response:
I think it's this line of code, Just get rid of it
<p>Total: {{product.details(product.count, product.value)}}</p>