Vue.js v-model with dynamic list of radio buttons

Tom picture Tom · Oct 28, 2019 · Viewed 12.1k times · Source

I am trying to make a reuseable vue radio-button component that will take a variable name, and an object containing labels and values, then render a list of radio buttons using v-for.

I have had success with each half of the problem, but have not managed to combine them:

  1. I can make a set of radio buttons bound to the data model, where the buttons are defined statically in the template, but I don't know how to make the list dynamic. Here is the code for that:

  1. I can make a dynamic list of radio buttons based on an "options" object, but can't find a way to bind them to the data model. Here is the code for that:

// component
Vue.component('radio-set', {
  template: '#radio-set',
  props: {
			'label-name': '',
			'variable': '',
			'options': '',
		},
  methods: {
    clicked: function(variable, key, value) {
    // none of this is right, it doesn't update the vue data model
		window[variable] = value; //assign the new value to the dynamic variable name
		selected = value;
		this.$emit("click-event", variable) //create the click event for model updating by the parent
    }
  },
})

//app
var app = new Vue({
  el: '#vueApp',
  data: {
    door:'initial value',
		doorOptions: {
		  'Yes':1,
		  'No':0,
      'Maybe':5,
      'A new option':25
		},
		
  },
  methods: {
		buttonClick: function(p1){
			console.log(p1+': '+window[p1]); //the variable was assigned inside the child component
		}
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="vueApp">
	<radio-set 
		label-name="Radio button set" 
		variable="door" 
		:options="doorOptions"
		@click-event="buttonClick" 
	>door: {{door}}
	</radio-set>
</div>

<template id="radio-set">
	<div>
		<label>{{labelName}}:</label>
		<button 
      type="button" 
      v-for="(val, key) in options"
      @click="clicked(variable, key, val)" 
      >
      {{ key }}
		</button>
	 </div>
</template>

Could anyone help with a couple of pointers on how I could move forwards?

Answer

Ja9ad335h picture Ja9ad335h · Oct 28, 2019

As @PierreSaid mentioned, you can read more about v-model usage on custom componet.

This is an other example to use input[type="radio"] and emit change event back to parent componet.

// component
Vue.component('radio-set', {
  template: '#radio-set',
  props: {
    'label-name': '',
    'value': '',
    'options': '',
  }
})

//app
var app = new Vue({
  el: '#vueApp',
  data() {
    return {
      door: null,
      doorOptions: {
        'Yes': 1,
        'No': 0,
        'Maybe': 5,
        'A new option': 25
      }
    };
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="vueApp">
  <radio-set label-name="Radio button set" v-model="door" :options="doorOptions"></radio-set>
  door: {{door}}
</div>

<template id="radio-set">
  <div>
    <div>{{labelName}}:</div>
    <label v-for="(val, key) in options" :key="val">
      <input type="radio" 
        :name="labelName" 
        :value="val" 
        :checked="val == value" 
        @change="$emit('input', val)"> 
      {{ key }}
    </label>
  </div>
</template>