Reputation: 3327
The rows of a table are generated using a v-for
loop over an array of objects in graphicState
. I am trying to create a column of radio buttons. When a radio button is checked, this should set graphicState[index].selected
to true
.
This post is interesting, but how can I use it set graphicState[index].selected
to true
?
<form>
<div class="row">
<div class="col-md-12 " align="center">
<table class="table-striped" v-on:mouseleave="mouseleave()">
<thead>
<tr>
<th></th>
<th>Show</th>
<th>Select</th>
<th>Shape</th>
</tr>
</thead>
<tbody>
<tr v-for="(form, index) in graphicState" :key="index">
<td @click="removeDate(index)"><i class="far fa-trash-alt"></i></td>
<td>
<input type="checkbox" v-model="form.show">
</td>
<td>
<input type="radio" name="grp" id="grp" value="true" v-model="form.selected">
</td>
<td v-on:click="toggleShape(index)">
{{ form.shape }}
</td>
</tr>
</tbody>
</table>
<div v-for="(form, index) in graphicState " :key="index">
</div>
</div>
</div>
</form>
Upvotes: 1
Views: 664
Reputation: 138226
The code you have already should set the graphicState[index].selected
to true
for the radio inputs, but the input values (and thus graphicState[index].selected
through v-model
) are never set to false
, which is a problem if the user is allowed to change their mind to select a different input. This occurs because the radio input's change
-event is only fired when the its checked
property is set to a truthy value (upon selection).
One solution is to add a change
-event handler that clears the .selected
value for the non-selected inputs.
// template
<tr v-for="(form, index) in graphicState">
<input @change="onRadioChange(index)" ...>
</tr>
// script
onRadioChange(selectedIndex) {
this.graphicState
.filter((x,i) => i !== selectedIndex) // get non-selected inputs
.forEach(x => x.selected = false)
}
But there's still another problem if you're using HTMLFormElement
's native submit. In the following template, when the v-model
value is true
, Vue sets the radio input's checked
property to true
, which tells the HTMLFormElement
to use this particular input's value as the group value
...
<input type="radio"
name="grp"
v-model="form.selected"
value="true">
All the radio inputs have the same value, so the receiver of the form data won't be able to tell which input is selected. To address this, assign a unique value to each input based on the iterator item. For example, you could use ID:
<input type="radio"
name="grp"
v-model="form.selected"
value="form.id">
new Vue({
el: '#app',
data() {
return {
graphicState: [
{id: 'A', selected: false, show: false},
{id: 'B', selected: false, show: false},
{id: 'C', selected: false, show: false},
]
}
},
methods: {
mouseleave() {},
removeDate() {},
toggleShape() {},
onRadioChange(selectedIndex) {
this.graphicState
.filter((x,i) => i !== selectedIndex)
.forEach(x => x.selected = false)
},
}
})
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<div id="app">
<form method="post" action="//httpbin.org/post">
<div class="row">
<div class="col-md-12" align="center">
<table class="table-striped" v-on:mouseleave="mouseleave()">
<thead>
<tr>
<th></th>
<th>Show</th>
<th>Select</th>
<th>Shape</th>
</tr>
</thead>
<tbody>
<tr v-for="(form, index) in graphicState" :key="form.id">
<td @click="removeDate(index)"><i class="far fa-trash-alt"></i></td>
<td>
<input type="checkbox" v-model="form.show">
</td>
<td>
<input type="radio" name="grp" :value="form.id" v-model="form.selected" @change="onRadioChange(index)">
</td>
<td v-on:click="toggleShape(index)">
{{ form.shape }}
</td>
</tr>
</tbody>
</table>
<pre>{{graphicState}}</pre>
</div>
</div>
<button>Submit</button>
</form>
</div>
Upvotes: 1
Reputation: 22393
You can use @change
event handler:
<input type="radio" name="grp" id="grp" value="true" v-model="form.selected" @change="onChange($event, index)">
then handle in method:
methods: {
onChange (event, index) {
this.graphicState[index].selected = event.target.value
this.graphicState = JSON.parse(JSON.stringify(this.graphicState))
}
}
Upvotes: 2