0

I have a dataset that looks like this:

[
    {id: 1, name: 'Foo', is_primary: false},
    {id: 2, name: 'Bar', is_primary: true},
    {id: 3, name: 'Baz', is_primary: false},
]

Only one of the entries is allowed to have is_primary = true. I'm displaying these items in a list, and I'm trying to display a radio button for each that the user can select to indicate that this is the primary one.

<tr v-for="item in items">
    <td><input name="primary" type="radio" v-model="item.is_primary"></td>
</tr>

However, I don't think I'm understanding how this is supposed to work, because it's not working for me. Is this possible or am I supposed to handle this situation another way?

1 Answer 1

3

A set of radio inputs should v-model the same variable: a scalar that takes on the value associated with the selected radio.

To translate that back and forth into your item list, you can use a settable computed.

new Vue({
  el: '#app',
  data: {
    items: [{
        id: 1,
        name: 'Foo',
        is_primary: false
      },
      {
        id: 2,
        name: 'Bar',
        is_primary: true
      },
      {
        id: 3,
        name: 'Baz',
        is_primary: false
      },
    ]
  },
  computed: {
    primaryItem: {
      get() {
        return this.items.find((i) => i.is_primary);
      },
      set(pi) {
        this.items.forEach((i) => i.is_primary = i === pi);
      }
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div v-for="item in items">
    <input name="primary" type="radio" :value="item" v-model="primaryItem">
  </div>
  <pre>{{JSON.stringify(items, null, 2)}}</pre>
</div>

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you. This seems like such a common scenario. I’m surprised all this code is needed. Why can’t each radio just bind to the attribute on its model?
Probably because the usual data model for having a single item selected is a scalar that indicates which is selected rather than a separate boolean for each item.
Right but the Boolean is what needs to get passed to the server, and I need to create a variable and a getter and setter just to have the Boolean set. Seems like a lot of work. There must be a reason it can’t be done that way. Regardless, thanks!
You could make primaryItem a real data item and just calculate is_primary when you're sending to the server.
Still it seems like it shouldn’t have to be specially handled or calculated. It should just be another attribute on the model that gets manipulated on the page and sent to the server like any other attribute. Like if I want to bind the name to a text field, I can just use v-model, type whatever I want, and send the current attribute’s value to the server to save. With is_primary I can’t do that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.