6

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
         },
1

2 Answers 2

19

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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 Yup, many ways to clone an array. Glad you found one that worked for you.
3

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());
});

2 Comments

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.
No this should not be an accepted answer because it causes an internal infinite loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.