Bishwas
Bishwas

Reputation: 203

How to make radio buttons with same value reusable?

I am a beginner to Vue, and learning something by doing. I was able to make a checkbox reusable, but getting some weird result for radio buttons. I have the data in an array format in ProgramDesign.vue:

data() {
  return {
    strategies: [
      "Not Important",
      "Slightly Important",
      "Moderately Important",
      "Very Important",
      "Extremely Important",
    ],
  };
},

These are the options that get repeated on every question. I made a separate component for the radio like this:

<template>
  <div>
    <span v-for="strategy in groups" :key="strategy">
      <input :id="strategy" class="radio-style" name="strategy" type="radio" />
      <label :for="strategy" class="radio-style-3-label">{{strategy}}</label>
    </span>
  </div>
</template>
<script>
export default {
  props: {
    groups: Array,
  },
};
</script>

This is how it's used in ProgramDesign.vue:

<p>first question goes here ?</p>
<RadioButton :groups="strategies" />
<div class="line"></div>
<p>second question goes here ?</p>
<RadioButton :groups="strategies" />

I was able to get the reusable output, but when I click on the radio button for the second question, the buttons for the first question get selected. How can I fix this?

Upvotes: 3

Views: 1117

Answers (1)

tony19
tony19

Reputation: 138696

The problem is the input IDs and names are not unique between component instances, as can be seen in the rendering of your two RadioButton components (simplified for brevity):

<!-- RadioButton 1 -->
<div>
  <span>
    <input id="Not Important" name="strategy" type="radio">
    <label for="Not Important">Not Important</label>
  </span>
</div>

<!-- RadioButton 2 -->
<div>
  <span>
    <input id="Not Important"❌ name="strategy"❌ type="radio">
    <label for="Not Important">Not Important</label>
  </span>
</div>

Each label is linked to an input by matching the for and id attributes, such that clicking the label causes the linked radio input to change values. When there are multiple inputs with the same identifier, the browser links the label to the first matching input, causing the behavior you observed.

The name must also be unique between groups (RadioButton instances), since the browser creates radio groups of inputs that have matching names.

Solution

Alternatively, a label and input can be linked by putting the input inside the label, resolving the id/for duplication (and improving readability):

<label>
  <input name="strategy" type="radio">
  Not Important
</label>

And one way to resolve the duplicate names is to base the name on a counter incremented per instance:

<template>
  <div>
    <label v-for="strategy in groups" :key="strategy">
      <input :name="'strategy' + groupId" type="radio">
      {{strategy}}
    </label>
  </div>
</template>

<script>
let groupId = 0

export default {
  props: {
    groups: Array
  },
  data() {
    return {
      groupId: groupId++
    }
  }
}
</script>

Edit Troubleshooting label and input pairs

Upvotes: 5

Related Questions