rado
rado

Reputation: 111

Vue.js select multiple value

I'm trying to set value to select with multiple=true within vue.js. When I'm setting v-model, everything is ok

<select v-model="selected" multiple style="width: 50px;">

but when I'm setting v-bind:value no value is selected in select tag

<select v-bind:value="selected" multiple style="width: 50px;">

Example Code

How can I set read-only value to select?

Update: I'm using this in component, so v-model can't be used, I have to use v-bind:value + v-on:change pair. Change function already done and works like a charm, so no question regarding it.

Upvotes: 2

Views: 16959

Answers (3)

Charles Jourdan
Charles Jourdan

Reputation: 810

I had the same problem. I searched for some hours to find a solution to forward the value and event.

I started my research in reading source code and I find some interesting things. When you use v-model, vue.js generates a piece of code at runtime. These code retreat the event to simplify the assignement.

This save my life for the case when the select is not multiple, but the problem stayed. I suppose there is something similar for the binding of attribute value, but I didn't find it. If someone have it, I'm interested to have the source.

Finally I found a simple solution. The aim is just forwarding the v-model interactions of select (bind value and input event). I create a component with:

  • computed property model with a getter and setter.
  • a prop value.

With these, we take advantages of the generated piece of code with the setter, because the value passed is the refined value. The getter don't need to be more complex.

{
  props: ["value"],
  computed: {
    model: {
      get: () => {
        // value is a prop of the component
        return this.value;
      },

      set: (valueSelect) => {
        this.$emit("input", valueSelect);
      }
    }
  }
}

The template :

<template>
  <select v-model="model">
    <slot></slot>
  </select>
</template>

I hope this help.

Sorry for the syntax, but I'm writing component in Typescript so it is really different. I write here in typescript and sfc syntax.

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { Prop, Watch } from "vue-property-decorator";

@Component
export default class SelectComponent extends Vue {
  @Prop({
    required: true
  })
  private value: any[] | any;

  @Prop({
    default: false
  })
  private multiple: boolean;

  private get model() {
    return this.value;
  }

  private set model(value) {
    this.$emit("input", value);
  }
}
</script>
<template>
  <select v-model="model" :multiple="multiple">
    <slot></slot>
  </select>
</template>

Upvotes: 1

mom2000
mom2000

Reputation: 21

I'm not sure, but it may be an option:

new Vue({
  el: '#example-6',
  data: {
    selected: ['A', 'B'],
    options: ['A', 'B', 'C']
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="example-6" class="demo">
  <select multiple style="width: 50px;">
     <option v-for="option in options" :selected="selected.indexOf (option) != -1">{{option}}</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>

Upvotes: 2

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

I think you wanted to do:

<div id="example-6" class="demo">
  <select multiple disabled v-model="selected" style="width: 50px;">
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>

Your updated jsfiddle.

v-model actually uses v-bind behind the scenes. If you only use v-bind you'll be missing the input event handling and no change to the input will be propagated to the state.

Update:

Using v-bind:value, it's only possible to select one option:

v-bind:value="selected[0]" // in the select tag

And you may also do like:

<div id="example-6" class="demo">
  <select multiple disabled style="width: 50px;">
    <option :selected="selected[0]">A</option>
    <option :selected="selected[1]">B</option>
    <option :selected="selected[2]">C</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>

jsfiddle

Here's a more elegant way for this:

<div id="example-6" class="demo">
  <select multiple disabled style="width: 50px;">
    <option v-for="(option, index) in options" :selected="selected[index]">
    {{ option }}
  </option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>

jsfiddle

Upvotes: 0

Related Questions