So i am passing an object having length of data and the data itself which is an array of objects
Now what is happening is that when I change the data in the child component and reload the page the data is still showing the edited property
To clarify more see the following screenshots:
When we navigate to the route for the first time there would be no modified data:
When I edit the data:: As you can see on the right side finalAmount property is added and its value is initialised
Now when renavigate to the same component finalAmount is set to 5
The property itself should not be present in the data as I am getting it from the parent
These are the relevant files:
- stepper.component.html (Parent Component)
<mat-step [stepControl]="thirdFormGroup" >
<ng-template matStepLabel>Prepare Invoice</ng-template>
<ng-template matStepContent>
<div >
<app-create-invoice [selectedCustomersInfo]="selectedCustomerData"
[selectedProductsData]="{lengthOfData:cartItems.length , selectedProducts:cartItems}"></app-create-invoice>
</div>
</ng-template>
</mat-step>
- stepper.component.ts:
@Component({
selector: 'app-stepper',
templateUrl: './stepper.component.html',
styleUrls: ['./stepper.component.scss'],
providers: [
{
provide: STEPPER_GLOBAL_OPTIONS,
useValue: { showError: true }
}
]
})
export class StepperComponent implements OnInit, OnDestroy {
getProductsSubscription = new Subscription
cartItems: ProductDataModel[] = []
selectedCustomerData: any
products = this._formBuilder.group({
firstCtrl: ['', Validators.required],
});
thirdFormGroup = this._formBuilder.group({
thirdCtrl: ['', Validators.required],
});
stepperOrientation: Observable<StepperOrientation>;
constructor(private _formBuilder: FormBuilder, breakpointObserver: BreakpointObserver, private cartService: CartService) {
this.stepperOrientation = breakpointObserver
.observe('(min-width: 800px)')
.pipe(map(({ matches }) => (matches ? 'horizontal' : 'vertical')));
}
ngOnDestroy(): void {
console.log("Stepper destroyed");
this.getProductsSubscription.unsubscribe()
}
ngOnInit(): void {
this.getProductsSubscription = this.cartService.getProducts().subscribe((items) => {
this.cartItems = [...items]
console.log("Cart items::", this.cartItems)
})
}
setCustomerData(customerData: any) {
this.selectedCustomerData = customerData
}
}
- create-invoice.component.html (Child Component):
<div >
<table >
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Product Category</th>
<th scope="col">Sub Category</th>
<th scope="col">Master Category</th>
<th scope="col">Product Weight</th>
<th scope="col">Price</th>
<th scope="col">Labour</th>
<th scope="col">SGST (In %)</th>
<th scope="col">CGST (In %)</th>
<th scope="col">Discount</th>
<th scope="col">Final Amount</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of _selectedProductsData;index as i">
<th scope="row">{{i 1}}</th>
<td>{{item.productCategory}}</td>
<td>{{item.subCategory}}</td>
<td>{{item.masterCategory}}</td>
<td>{{item.productWeight}} gms</td>
<td>
<input type="number" id="{{item.productGuid}}-price"
min="0" (input)="item.price = getValue($event,item.id,'price')" #price
placeholder="Enter Price">
</td>
<td>
<input type="number" id="{{item.productGuid}}-labour"
min="0" (input)="item.labour = getValue($event,item.id,'labour')" #labor
placeholder="Enter Labour">
</td>
<td>
<input type="number" id="{{item.productGuid}}-SGST"
min="0" (input)="item.SGST = getValue($event,item.id,'sgst')" #sgst
placeholder="Enter SGST">
</td>
<td>
<input type="number" id="{{item.productGuid}}-CGST"
min="0" (input)="item.CGST = getValue($event,item.id,'cgst')" #cgst
placeholder="Enter CGST">
</td>
<td>
<input type="number" min="0"
(input)="item.discount = getValue($event,item.id,'discount')" #discount
id="{{item.productGuid}}-discount" placeholder="Enter Discount">
</td>
<td>
{{ item.finalAmount ?? 0 }}
<input type="hidden" [value]="item.finalAmount ?? 0">
</td>
</tr>
</tbody>
</table>
</div>
- create-invoice.component.ts:
@Component({
selector: 'app-create-invoice',
templateUrl: './create-invoice.component.html',
styleUrls: ['./create-invoice.component.scss']
})
export class CreateInvoiceComponent implements OnInit,OnDestroy {
_selectedCustomersInfo:any
_selectedProductsData:InvoiceProductDataModel[] = []
totalWeight = 0
totalDiscount = 0
totalGST = 0
totalAmountWithGST = 0
currentDate:Date = new Date()
@Input() set selectedProductsData(productsData: {lengthOfData:number,selectedProducts:ProductDataModel[]}) {
this.totalWeight = 0
this.totalDiscount = 0
this.totalAmountWithGST = 0
this.totalGST = 0
var temp = Object.assign({},productsData)
this._selectedProductsData = []
this._selectedProductsData = [...temp.selectedProducts]
// this._selectedProductsData = [...productsData.selectedProducts]
this._selectedProductsData.forEach((product) => {
this.totalWeight = product.productWeight
})
console.log(this._selectedProductsData)
}
@Input() set selectedCustomersInfo(customerInfo: any) {
this._selectedCustomersInfo = customerInfo
}
constructor() { }
ngOnDestroy(): void {
console.log("Create Invoice Destroyed!!")
this._selectedProductsData = []
}
ngOnInit(): void {
}
getValue(event: Event, productId:number, valueOf:string): number {
let product = this._selectedProductsData.find(item => item.id === productId)
if (product) {
switch (valueOf) {
case 'labour':
product.labour = Number((event.target as HTMLInputElement).value)
this.setFinalAmountOfEachProduct(product)
this.setTotalAmountWithGST()
break
case 'price':
product.price = Number((event.target as HTMLInputElement).value)
this.setFinalAmountOfEachProduct(product)
this.setTotalAmountWithGST()
break
case 'sgst':
product.SGST = Number((event.target as HTMLInputElement).value)
this.setFinalAmountOfEachProduct(product)
this.setTotalAmountWithGST()
this.setTotalGST()
break
case 'cgst':
product.CGST = Number((event.target as HTMLInputElement).value)
this.setFinalAmountOfEachProduct(product)
this.setTotalAmountWithGST()
this.setTotalGST()
break
case 'discount':
product.discount = Number((event.target as HTMLInputElement).value)
this.setFinalAmountOfEachProduct(product)
this.setTotalDiscount()
this.setTotalAmountWithGST()
break
}
}
console.log(this._selectedProductsData.find(i => i.id == productId))
return Number((event.target as HTMLInputElement).value);
}
setFinalAmountOfEachProduct(product:InvoiceProductDataModel) {
product.finalAmount = 0
let partialSum = (product.labour ?? 0) (product.price ?? 0) - (product.discount ?? 0)
let cgst = product.CGST ? partialSum * ((product.CGST ?? 100) / 100) : 0
let sgst = product.SGST ? partialSum * ((product.SGST ?? 100) / 100) : 0
product.totalGST = cgst sgst
product.finalAmount = partialSum cgst sgst
}
setTotalDiscount() {
this.totalDiscount = 0
this._selectedProductsData.forEach((item)=> {
this.totalDiscount = item.discount ?? 0
})
}
setTotalAmountWithGST() {
this.totalAmountWithGST = 0
this._selectedProductsData.forEach((item)=> {
this.totalAmountWithGST = item.finalAmount ?? 0
})
}
setTotalGST() {
this.totalGST = 0
this._selectedProductsData.forEach((item)=> {
this.totalGST = item.totalGST ?? 0
})
}
}
And its not limited to finalAmount
property it happens with other properties too like discount,sgst etc..
Any help will be appreciated
CodePudding user response:
From what I've understood you've got a problem with some data
that have been changed in parent but it's not updated in child component, that have received it thru @input()
. If I am right, you should read about Angular lifecycle hooks:
Also JSON.parse(JSON.stringify(productsData)) has its own limitations
For more information refer these links: