vuejs radio button component
Asked Answered
M

2

11

I trying to make this custom radio button component to work in vuejs. How do I make the radio button checked with a value from parent component. I know you use v-model and set it to a same value in one of the input values, but it dont seem to get it work.

component:

export default Vue.component('radioButton', {
  template,
  props: ['name', 'label', 'id', 'value']
})

component template:

<label class="radio" :for="id">
  <input type="radio" :id="id" class="radio-button" :value="value" :name="name">
   <span class="radio-circle">
  </span>
  <span class="radio-circle__inner">
  </span>
  <span class="radio-button__label">{{ label }}</span>
</label>

html:

<radio-button name="options" id="option-1" label="1" :value="selectedValue" />
<radio-button name="options" id="option-2" label="2" :value="selectedValue" />
Manzoni answered 7/11, 2016 at 21:7 Comment(1)
can you post a jsfiddle with what you've already done?Bawdyhouse
H
29

For radio buttons, you need to pass true or false for the checked property to preset it to some state. Alternatively, your value in v-model should be equal to value of radio button so that it gets checked.

In the limited sample code you have posted, I believe your label is the button index like 1, 2, 3 and so on... And I think you want to select one of the buttons when the selectedValue matches label of that radio button. For example, if selectedValue is 2, then you want radio button 2 to be checked.

Assuming the above is correct, you need to make a one line change in your radio-button component template:

<input type="radio" class="radio-button" :value="label" :name="name" v-model="value">

Note:

  1. Your button label is the value for radio button. This is what you would expect to set to selectedValue when you click a particular radio button.

  2. Your value in child component is actually selectedValue of parent component, which indicates the radio button that is currently chosen. So this should go into v-model

So, as per the docs on Form Input Bindings, your radio button will get checked if the v-model variable is equal to the value of that radio button.

But now here is another problem: If you click on another radio button, you expect the selectedValue in parent component to change. That is not going to happen because props gives you one-way binding only.

To resolve this issue, you need to do a $emit from your child component (radio button) and capture it in the parent component (your form).

Here is a working jsFiddle example: https://jsfiddle.net/mani04/3uznmk72/

In this example, your form template defines radio-button components as follows:

<radio-button name="options" label="1" :value="selectedValue" @change="changeValue"/>
<radio-button name="options" label="2" :value="selectedValue" @change="changeValue"/>

Whenever the value changes inside child component, it will pass a "change" event along with the label of radio button, which gets passed to changeValue() method of the parent form component. Once the parent component changes selectedValue, your radio buttons update automatically.

Hope it helps!

Hibernicism answered 8/11, 2016 at 10:20 Comment(1)
In order to reduce verbosity, since Vue.js 2.3.0, you can use the .sync modifier on the parent side and emit the event with the patternupdate:propName. Thus, defining @change is not required anymore. vuejs.org/v2/guide/components-custom-events.html#sync-ModifierAtmospheric
F
1

I'd personally do it another way, to keep a v-model directive and avoid an @change event (which could be replaced by @input if any other logic has to be performed). The thing here is that I the v-model value is equal to the "value" props in the radio-button component.

props: {
    value: {},
    v_value: {},
    ....
}

So all you have to do is pass the real current value to make some checks and $emit the value on click on a label, or on change on the input if you don't have any label.

<label :for="id" @click="$emit('input', v_value)">
      <input type="radio" :value="label" :name="name" :id="id" /> {{ label }}
</label>

I also added (but commented it) a version with simple html markup in case you want custom-looking radio buttons :

<div class="label" @click="$emit('input', v_value)">
      <span>{{ label }}</span>
</div>

https://jsfiddle.net/Zyfraglover/ndcp8t6e/

Firm answered 20/12, 2018 at 12:52 Comment(1)
This probably wouldn't work for keyboard based input and auxiliary devices.Tatiana

© 2022 - 2024 — McMap. All rights reserved.