Reputation: 25
I have an Order screen where I have a list of items to buy. In front of every item, I have a plus and minus button and an input field where I can specify the quantity of the item I need to buy. I am using *ngFor to iterate through an array and display the items. Even I am creating plus button, minus button and an input text field for that item using this *ngFor. I am using 2-way data binding to get and set the data into the input field.
But, the issue is, when I click the increment button, all the items are getting incremented instead of that particular item for which I clicked the plus button. Same issue with minus button as well.
This issue is because there is an only property which is getting bind to all the iterations of *ngFor.
<div class="row mt-2 mb-2" *ngFor="let item of listItems; let i = index">
<div class="col-sm-6">
<img src= "{{ item.imgUrl }}" alt="Item Img">
<span> {{ item.name.split(' ').slice(0,2).join(' ').replace(":", "").replace(",", "") }}</span>
</div>
<div class="col-sm-6 m-auto">
<button id="minus-image" class="minus mr-2" (click)="onMinusClick()"><img src="../../assets/icon/minus.png" alt="minus Img"></button>
<input type="text" id="buyNumInput" class="buyNum" [(ngModel)]="buyNumInput">
<button id="plus-image" class="plus ml-2" (click)="onPlusClick()"><img src="../../assets/icon/plus.png" alt="plus Img"></button>
<span class="price ml-3 text-right"> {{ item.price }} gold</span>
</div>
</div>
in .ts file:
buyNumInput = 0;
onPlusClick(){
this.buyNumInput++;
}
onMinusClick(){
this.buyNumInput--;
}
Expected result: When + or - button of that item is clicked then the input value of that item should be changed. All other items input values shouldn't be changed.
Upvotes: 1
Views: 3831
Reputation: 29745
Yes, that is because you are binding the same value buyNumInput
to all the items.
One way is to maintain separate array to store the values for each item. And when you click the button, pass the index of an item in the list. So that you increment/decrement it accordingly.
buyNumInput = [];
ngOnInit() {
for(let i=0; i<this.listItems.length; i++){
this.buyNumInput.push(0);
}
}
onPlusClick(i){
this.buyNumInput[i]++;
}
onMinusClick(i){
this.buyNumInput[i]--;
}
html code
<div class="row mt-2 mb-2" *ngFor="let item of listItems; let i = index">
<div class="col-sm-6">
<img src= "{{ item.imgUrl }}" alt="Item Img">
<span> {{ item.name.split(' ').slice(0,2).join(' ').replace(":", "").replace(",", "") }}</span>
</div>
<div class="col-sm-6 m-auto">
<button id="minus-image" class="minus mr-2" (click)="onMinusClick(i)"><img src="../../assets/icon/minus.png" alt="minus Img"></button>
<input type="text" id="buyNumInput" class="buyNum" [(ngModel)]="buyNumInput[i]">
<button id="plus-image" class="plus ml-2" (click)="onPlusClick(i)"><img src="../../assets/icon/plus.png" alt="plus Img"></button>
<span class="price ml-3 text-right"> {{ item.price }} gold</span>
</div>
Upvotes: 3
Reputation: 374
It seems you have just one number property in your component so it's shared between the items. One of the solutions could be: https://stackblitz.com/edit/angular-bbkun4
I recommend doing all the heavy string formatting inside .ts file(method 'getDisplayName') instead of directly inside the template.
typescript part:
getDisplayName(item) {
return item.name;
}
onPlusClick(item) {
item.count++;
}
onMinusClick(item) {
item.count = item.count === 0 ? 0 : item.count - 1;
}
onInputChanged(item, amount) {
item.count = amount;
}
and html:
<div *ngFor="let item of listItems; let i = index">
<div>
<img src="{{ item.imgUrl }}" alt="Item Img" />
<span> {{ getDisplayName(item) }}</span>
</div>
<div>
<button id="minus-image" (click)="onMinusClick(item)">
<img src="../../assets/icon/minus.png" alt="minus Img" />
</button>
<input
type="number"
id="buyNumInput"
[ngModel]="item.count"
(ngModelChange)="onInputChanged(item, $event)"
/>
<button id="plus-image" (click)="onPlusClick(item)">
<img src="../../assets/icon/plus.png" alt="plus Img" />
</button>
{{ item.price }} gold
</div>
</div>
Upvotes: 1