Uncheck radio button
Here goes a simple one without using v-model
and just only takes one variable for storing the current selected value.
var app = new Vue({
el: '#app',
data: {
list: ['one', 'two', 'three'],
selected: 'two'
},
methods: {
uncheck: function (val) {
if (val === this.selected) {
this.selected = false
} else {
this.selected = val
}
}
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<div v-for="(val, key) in list">
<input type="radio" :checked="selected===val" :id="val" @click="uncheck(val)" :key="'input' + key">
<label :for="val" :key="'label' + key">{{ val }}</label>
</div>
</div>
The difficulty is that v-model
is changing the value of selected
before you can examine it to see what its previous value is. You need another variable.
The idea is: when you click an item, it checks whether it matches previouslySelected
(rather than selected
). If it matches, unselect. Then set previouslySelected
to the value of selected
.
The click
handler should be on the input, not on the label; it is the function of the label to forward clicks to the input, anyway.
var app = new Vue({
el: '#app',
data: {
list: ['one', 'two', 'three'],
selected: 'two',
previouslySelected: 'two'
},
methods: {
uncheck: function(val) {
if (val === this.previouslySelected) {
this.selected = false;
}
this.previouslySelected = this.selected;
},
uncheckAll: function() {
this.selected = false;
}
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<div v-for="(val, key) in list">
<input type="radio" name="radio" :value="val" v-model="selected" :id="val" @click="uncheck(val)">
<label :for="val">{{ val }}</label>
</div>
<button @click="uncheckAll">Uncheck all</button>
</div>
set
to happen. (thanks to Vlad T. in the comments)
A more in-the-data way of approaching it would be to have a computed based on your selected, and have its setter do the check for re-selecting. No click handler. Everything is handled in the normal course of setting the value.
var app = new Vue({
el: '#app',
data: {
list: ['one', 'two', 'three'],
d_selected: 'two'
},
computed: {
selected: {
get() {
return this.d_selected;
},
set(v) {
if (v === this.d_selected) {
this.d_selected = false;
} else {
this.d_selected = v;
}
}
}
},
methods: {
uncheckAll: function() {
this.d_selected = false;
}
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<div v-for="(val, key) in list">
<input type="radio" name="radio" :value="val" v-model="selected" :id="val">
<label :for="val">{{ val }}</label>
</div>
<button @click="uncheckAll">Uncheck all</button>
</div>
You can use the prevent
modifier to prevent the default behavior of clicking the label:
<label :for="val" @click.prevent="uncheck( val )">{{ val }}</label>
Here's a working Codepen.