Reputation: 3486
I currently have the following scenario:
I have multiple checkboxes, once any is clicked, the value of it will get added to an array. If the checkbox is unchecked then the item needs to be removed out of the array again.
selectAddOn(addOnId) {
if (! this.selectedAddOns.includes(addOnId)) {
this.selectedAddOns.push(addOnId);
}
}
The following works and it adds them to my selectedAddOns[]
. But when the checkbox is checked again, it is not removed. Sure, I could just use else
, but...
Unfortunately, the browser behavior is when you click on a <label>
, a click event will automatically be triggered on the <input>
, so the outer div receives 2 events, one from label, one from input. I am aware that I can work around this by adding @click.prevent
on the <label>
, but this then will not add my custom checkbox styles.
<div @click="selectAddOn(index)" class="col-6" v-for="(addOn, index) in categories[categoryId].addOns">
<label class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input">
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{ addOn.name }} (+ ${{ addOn.price }})</span>
</label>
</div>
Any idea on how I can work around this scenario?
Upvotes: 1
Views: 3919
Reputation: 43899
This is a built-in behavior of v-model
when used with an array on multiple checkboxes. You don't need a click
handler. (Code shamelessly lifted from Bert's answer.)
console.clear()
new Vue({
el: "#app",
data:{
selectedAddOns:[],
categories:[
{
addOns:[
{name: "AddOn One", price: 10},
{name: "AddOn two", price: 20},
{name: "AddOn Three", price: 30},
]
},
],
categoryId: 0
}
})
<script src="https://unpkg.com/[email protected]"></script>
<div id="app">
Selected Addons: {{selectedAddOns}}
<div class="col-6" v-for="addOn, index in categories[categoryId].addOns">
<label class="custom-control custom-checkbox" >
<input type="checkbox" class="custom-control-input" :value="index" v-model="selectedAddOns" >
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{ addOn.name }} (+ ${{ addOn.price }})</span>
</label>
</div>
</div>
Upvotes: 4
Reputation: 82489
Put the click event handler on the input
.
console.clear()
new Vue({
el: "#app",
data:{
selectedAddOns:[],
categories:[
{
addOns:[
{name: "AddOn One", price: 10},
{name: "AddOn two", price: 20},
{name: "AddOn Three", price: 30},
]
},
],
categoryId: 0
},
methods:{
selectAddOn(addOnId) {
let index = this.selectedAddOns.findIndex(a => a === addOnId)
if (index >= 0)
this.selectedAddOns.splice(index, 1)
else
this.selectedAddOns.push(addOnId);
}
}
})
<script src="https://unpkg.com/[email protected]"></script>
<div id="app">
Selected Addons: {{selectedAddOns}}
<div class="col-6" v-for="(addOn, index) in categories[categoryId].addOns">
<label class="custom-control custom-checkbox" >
<input type="checkbox" class="custom-control-input" @click="selectAddOn(index)" >
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{ addOn.name }} (+ ${{ addOn.price }})</span>
</label>
</div>
</div>
Upvotes: 1