Reputation: 2480
i am new to angular.
Here is my test application.
https://stackblitz.com/github/tsingh38/lastrada (please click on Pizza) I have 2 components Pizza and Cart.
Pizza → PizzaunitComponent Cart→ CartComponent Once user has selected one of the listed Pizza. THe changes are being emitted on click of a button to a Cart Component. Where I am displaying the selected items.
onSubmit() {
this.orderedPizza.id = this.pizza.pizzaId;
this.orderedPizza.pizza=this.pizza;
this.orderedPizza.name = this.pizza.pizzaName;
this.orderedPizza.quantity = this.selectedQuantity;
this.orderedPizza.size = this.selectedSize;
this.orderedPizza.listOfAdditions = this.listOfCheckedPizzaAdditions;
this.orderedPizza.totalPrice = this.priceOnButton;
this.pizzaService.emitOrder( this.orderedPizza);
}
In Cart Component i am subscribing to the changes in ngOnInit
ngOnInit() {
this.cartService.pizzaOrderEmitter.subscribe(params => {
var recievedItem: ItemOrder;
if (params) {
recievedItem = new ItemOrder(params.id, params.pizza, params.name, params.size, params.listOfAdditions, params.quantity, params.totalPrice);
this.addItemToOrder(recievedItem);
} else {
this.orderedItems = [];
}
this.triggerPriceCalculation();
});
Problem is: Once the item is added to the Cart component. It can still be manipulated through Checkbox in the Pizza component. Though there is no emit event on checkbox click.(Add a item with one of the checkboxes ticked and after adding the item to Cart either uncheck the checkbox or check another checkbox)
I know that Angular checks for DOM changes and update the properties. But Changes are being made in the Pizza component which has no direct link to Cart Component. The information is only being passed using Observable.
<div class="form-group">
<span class="pull-left"> Ihre Extras:</span><br>
<div *ngFor="let pizzaAddition of allPizzaAdditions | slice:0:show;let i = index">
<input type="checkbox" value=pizzaAddition
(change)="fetchPriceForSelectedAddition(allPizzaAdditions[i],pizza, selectedPizzaSize,$event)" />
<span> mit {{pizzaAddition.nameOfAddition}}</span>
<span>({{displayPizzaAdditionPriceForSelectedPizzaSize(selectedPizzaSize,pizzaAddition.nameOfAddition)==0?pizzaAddition.price:displayPizzaAdditionPriceForSelectedPizzaSize(selectedPizzaSize,pizzaAddition.nameOfAddition)}}€)</span><br>
<a *ngIf="i==2 && show == 3" (click)="show = allPizzaAdditions.length">
<span class="glyphicon glyphicon-chevron-down"></span>
</a>
</div>
displayPizzaAdditionPriceForSelectedPizzaSize(selectedPizzaSize: HTMLSelectElement, currentPizzaAddition: PizzaAdditions) {
if (selectedPizzaSize.value.length > 0) {
return this.pizzaService.fetchPriceOfAPizzaAdditionsAccordingToSize(selectedPizzaSize.value, currentPizzaAddition.id);
}
return 0;
}
In Service
fetchPriceOfAPizzaAdditionsAccordingToSize(selectedSize: String, selectedAddition: String) {
switch (selectedSize) {
case 'Small 26': return 0.50;
case 'Normal 28': return 1;
case 'Family 32': return 1.50;
case 'Party 38': return 2;
default: return 0.50;
}
}
My expectations are that once the item has been added to the Arrays. It should not be manipulated externally any how and i would like to know why this is happening.
Upvotes: 0
Views: 77
Reputation: 11464
There are a few ways that this could be solved, but the root cause is the fact that your pizza object is passed by reference. Therefore when you make changes to the pizza in the Pizza component, those changes are being reflected in the Order component. What you would want to do somewhere along the chain would be to create a new pizza object and pass it along.
The easiest way around this would most likely be to utilize the spread operator before emitting the pizza. Something like this. This will create a copy of the pizza object and pass that copy along up the chain. Therefore the pizza object in your Pizza component will be different from the one in the Order component.
this.pizzaService.emitOrder({...this.orderedPizza});
Upvotes: 2
Reputation: 1783
This happens because objects in JavaScript are passed by reference. So your this.pizza
in pizzaunit.component.ts
and the pizza
in the orderedPizza
object reference the same object.
You can make a shallow copy of the pizza in the onSubmit
to avoid this. The same has to be made with the listOfCheckedPizzaAdditions
, which are also passed by reference.
onSubmit() {
this.orderedPizza.id = this.pizza.pizzaId;
this.orderedPizza.pizza= {...this.pizza}; // Shallow copy
this.orderedPizza.name = this.pizza.pizzaName;
this.orderedPizza.quantity = this.selectedQuantity;
this.orderedPizza.size = this.selectedSize;
this.orderedPizza.listOfAdditions = [...this.listOfCheckedPizzaAdditions]; // same here
this.orderedPizza.totalPrice = this.priceOnButton;
this.pizzaService.emitOrder( this.orderedPizza);
}
Upvotes: 3