0

The radio buttons' behavior is not as I expected when I am being lazy to use v-bind to dynamically bind the properties of the options to the template.

I am trying to dynamically render the options by an javascript object. However, it behaves differently when I am binding the properties differently. Even after checking the output HTML, I am not sure why the problem exists.

This is the Vue instance for backend data.

const app = new Vue({
        el: '#app',

        data: {
            inputs: {
                radioDynamic: '',
                radioDynamicOptions: [
                    {
                        id: 'Light',
                        label: 'Blue',
                        value: 'Light',
                    },
                    {
                        id: 'Dark',
                        label: 'Red',
                        value: 'Dark',
                    },
                ],
            },
        },
        template: `
        <div>
            <h4>Radios Dynamic Options</h4>

            <!-- case 1: It works fine when I bind properties individually> 

            <template v-for="(option, index) in inputs.radioDynamicOptions">
                <input v-model="inputs.radioDynamic" type="radio" :value="option.value" :id="option.value">
                <label :for="option.value">{{ option.label }}</label>
                <br v-if="index < inputs.radioDynamicOptions.length">
            </template>
            -->

            <!-- case 2: the options are rendered as a single radio button which is not able to function correctly when I bind the object directly with v-bind="object". 

            <template v-for="(option, index) in inputs.radioDynamicOptions">
                <input v-model="inputs.radioDynamic" type="radio" v-bind="option">
                <label :for="option.value">{{ option.label }}</label>
                <br v-if="index < inputs.radioDynamicOptions.length">
            </template>
            -->

            <p><strong>Radios:</strong>{{ inputs.radioDynamic }}</p>
        </div>
        `,
})




<case 1 HTML output>
<h4>Radios Dynamic Options</h4> 
<input type="radio" id="Light" value="Light"> 
<label for="Light">Blue</label> 
<br>
<input type="radio" id="Dark" value="Dark"> 
<label for="Dark">Red</label> 
<br> 
<p><strong>Radios:</strong>Dark</p>

<case 2 HTML output>
<h4>Radios Dynamic Options</h4> 
<input type="radio" id="Light" label="Blue" value="Light"> 
<label for="Light">Blue</label> 
<br>
<input type="radio" id="Dark" label="Red" value="Dark"> 
<label for="Dark">Red</label> 
<br> 
<p><strong>Radios:</strong></p>

I expect the case 2 method, which is using v-bind="object", should generate the same result like v-bind:id="object.id" v-bind:value="object.value" But it turns out that I can't select the radio button individually and the selected value isn't pushed into the array.

This is my very first question here. Please forgive if my expression or format isn't good or qualified enough. Thanks and have a great day~

Chan Xens
  • 43
  • 4

2 Answers2

0

not sure what you're trying to achieve here, but i would recommend going over the functionality of v-bind and v-model. v-bind enables passing dynamic data to html attributes. v-on allows listening to DOM events, and v-model results in whats called - two way data binding, which is basically a combination of both v-bind and v-on. with that said, using both v-model and v-bind on the same element feel's a bit odd.

you might achieve what you desire in the 2nd case following way:

 <template v-for="(option, index) in inputs.radioDynamicOptions">
      <input v-model="inputs.radioDynamic" type="radio" v-bind:value="option.id">
      <label :for="option.value">{{ option.label }}</label>
      <br v-if="index < inputs.radioDynamicOptions.length">
 </template>

UPDATE:

i believe that the issue your'e experiencing is a result of one main difference between object (which you can learn more about here) and primitive types. long story short, in JavaScript primitive types like the strings you pass in case 1 are being passed by value and so behave as expected. while passing object's to v-bind you actually pass a pointer to that object and so when you click a radio button, you manipulate the same place in memory in charge of both radio buttons, which results with the unexpected behavior you experience.

yariv bar
  • 936
  • 3
  • 20
  • 39
  • Thank you yariv. Yes, it is trivial to do so as case 2. – Chan Xens Jan 09 '19 at 10:22
  • you welcome! please except the answer/mark as useful if indeed it was, to help people with the same question find an answer in the future (and for my own benefit :))) – yariv bar Jan 09 '19 at 10:30
  • I am just wondering why case 2 can't achieve the same behavior like case 1. AFAIK, ****. Hence, it should work similar like case 1. However, if I apply the code of case 2, the behavior of the rendered buttons is not as I expected so I am just wondering why it is. – Chan Xens Jan 09 '19 at 10:31
  • i see what you mean, updated my answer, think it might be what you're looking for – yariv bar Jan 09 '19 at 20:03
  • Thanks Yariv. You gave a perfect answer to solve my puzzle :) – Chan Xens Jan 16 '19 at 06:51
0

Why do you expect that v-bind="options" will work on <input/>? This form is used for custom components only.

From documentation:

Components In-Depth → Props → Passing the Properties of an Object

If you want to pass all the properties of an object as props, you can use v-bind without an argument (v-bind instead of v-bind:prop-name). For example, given a post object:

post: {
  id: 1,
  title: 'My Journey with Vue'
}

The following template:

<blog-post v-bind="post"></blog-post>

Will be equivalent to:

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title">
</blog-post>

If you want to bind dynamic/javascript values to an usual element, you should use :value="option.value" :id="option.id" as shown in your first example.

tony19
  • 125,647
  • 18
  • 229
  • 307
Styx
  • 9,863
  • 8
  • 43
  • 53