5

For many days I've searched to find an answer to this error. I tried many alternatives but nothing worked.

I need to select multiple values. When I select multiple values, my code hangs, but when I use a single select it works well with self.$emit('input', this.value). What I need is to select multiple values.

Select2.vue

<template>
    <select multiple class="input-sm" :name="name">
        <slot></slot>
    </select>
</template>
<style src="select2/dist/css/select2.min.css"></style>
<style src="select2-bootstrap-theme/dist/select2-bootstrap.min.css"></style>

<script>
    import Select2 from 'select2';

    export default{
        twoWay: true,
        priority: 1000,
        props: ['options', 'value', 'name'],
        data(){
            return{
                msg: 'hello'
            }
        },
        mounted(){
            var self = this;
            $(this.$el)
                .select2({theme: "bootstrap", data: this.options})
                .val(this.value)
                .trigger('change')
                .on('change', function () {
                    //self.$emit('input', this.value) //single select worked good
                    self.$emit('input',  $(this).val()) // multiple select
                })
        },
        watch: {
            value: function (value) {
                $(this.$el).val(value).trigger('change');
            },
            options: function (options) {
                $(this.$el).select2({ data: options })
            }
        },
        destroyed: function () {
            $(this.$el).off().select2('destroy')
        }
    }
</script>

new.vue

    <p>Selected: {{ model.users_id }}</p>
              <select2 :options="options" v-model="model.users_id" name="options[]" style="width: 1000px; height: 1em;" class="form-control">
           <option value="0">default</option>
            </select2>

    export default {
            data(){
                return {
                    model: {
                        'users_id': [],
                    },
                    options: [],

components:{
            'select2': Select2
         },
Bert
  • 80,741
  • 17
  • 199
  • 164
fido
  • 148
  • 1
  • 2
  • 14
  • This work for me: https://stackoverflow.com/questions/35154138/using-select2-multiple-selections-with-vue-js/44485305#44485305 – aleixfabra Jun 11 '17 at 15:08

2 Answers2

18

It looks like you used the Vue documentation example of a wrapper for select2 as your base. I've modified the wrapper to handle a multiple select here.

I expect the main issue you were running into is that if you do this:

self.$emit('input',  $(this).val()) // multiple select

You will end up in an infinite loop, because you are emitting a new array, which is going to trigger the watch,

value: function (value) {
    $(this.$el).val(value).trigger('change');
},

which triggers the change, which triggers the watch, etc.

To fix that, just check to see if the value passed into the watch is identical to the values of the select, and if it is, ignore it. Here's how I did that.

value: function (value) {
  // check to see if the arrays contain the same values
  if ([...value].sort().join(",") !== [...$(this.$el).val()].sort().join(","))
    $(this.$el).val(value).trigger('change');
},

Notice also that I turned this into it's own component, select2Multiple. You might want to have one component that handles multiple selected values and another for single values.

Bert
  • 80,741
  • 17
  • 199
  • 164
  • Is there a way to do this without using spread notation? EDIT: figured it out. Use `Array.from(value).sort()...` and `Array.from($(this.$el).val())...` – flyingfisch Jun 29 '17 at 14:20
  • @flyingfisch Yup, many ways to clone an array. Glad you found one that worked for you. – Bert Jun 29 '17 at 14:34
2

As I answered here: Using Select2 (multiple selections) with vue.js

Change this:

.on('change', function () {
  self.$emit('input', this.value); // Don't use this.value
});

To this:

.on('change', function () {
  self.$emit('input', $(this).val());
});
aleixfabra
  • 1,075
  • 3
  • 11
  • 24
  • This should be the accepted answer. Works for both multi select and single select, avoiding having to create a new select2 component just for a multiselect. – Taylor Foster May 31 '19 at 14:17
  • 4
    No this should not be an accepted answer because it causes an internal infinite loop. – Tomsgu Aug 06 '19 at 08:00