Binding a Select2 select to a Vue js model data
Asked Answered
O

4

13

I'm using select2 to enhance an html select element. I want to bind the value of the select element to a Vue variable, however the Select2 seems to be preventing this.

What's the best way to achieve this data binding and event listening whilst retaining the Select2 behaviour. I imagine it's a case of linking the select2 events to the Vue instance.

I've made a fiddle demonstrating the problem (does not run below but works on jsfiddle):

$('#things').select2();

new Vue({
  el: "#vue-example",
  data: {
    thing: null,
    thing2: null
  },
  methods: {
    log: function(str) {
      $('#log').append(str + "<br>");
    }
  }
});
select {
  width: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.8/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<div id="vue-example">
  <label>Select2 Select Box</label>
  <select name="things" id="things" v-model="thing" v-on="change: log('you changed thing1')">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
    <option value="5">Five</option>
  </select>
  <br>
  <br>
  <label>Native Select Box</label>
  <select name="things" id="things" v-model="thing2" v-on="change: log('you changed thing2')">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
    <option value="5">Five</option>
  </select>
  <pre>{{ $data | json }}</pre>
  <div id="log">

  </div>
</div>
Ostracon answered 24/7, 2015 at 10:23 Comment(1)
Also check this solution : https://mcmap.net/q/849676/-select2-on-change-event-is-not-working-in-vuejs/2815635Doreathadoreen
P
20

A shorter solution:

Vue.directive('select2', {
    inserted(el) {
        $(el).on('select2:select', () => {
            const event = new Event('change', { bubbles: true, cancelable: true });
            el.dispatchEvent(event);
        });

        $(el).on('select2:unselect', () => {
            const event = new Event('change', {bubbles: true, cancelable: true})
            el.dispatchEvent(event)
        })
    },
});

Trae's answer is good but the value is already being stored on the select element, so all you have to do, is dispatch the event to let Vue know that we have changed it.

Just simply do:

<select v-model="myprop" v-select2>
...
Parhelion answered 10/7, 2018 at 8:40 Comment(0)
F
9

swift's answer is correct. You just need to identify and update that code to reflect the differences in Select2.

http://jsfiddle.net/qfy6s9Lj/10/

Vue.directive('selecttwo', {
  twoWay: true,
  bind: function () {
    $(this.el).select2()
    .on("select2:select", function(e) {
      this.set($(this.el).val());
    }.bind(this));
  },
  update: function(nv, ov) {
    $(this.el).trigger("change");
  }
});

new Vue({
  el: "#vue-example",
  data: {
    thing: null,
    thing2: null
  },
  methods: {
    log: function(str) {
      $('#log').append(str + "<br>");
    }
  }
});
select {
  width: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.8/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<div id="vue-example">
  <label>Select2 Select Box</label>
  <select name="things" id="things" v-model="thing" v-selecttwo="thing" v-on="change: log('you changed thing1')">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
    <option value="5">Five</option>
  </select>
  <br>
  <br>
  <label>Native Select Box</label>
  <select name="things" id="things" v-model="thing2" v-selecttwo="thing2" v-on="change: log('you changed thing2')">
    <option value="1">One</option>
    <option value="2">Two</option>
    <option value="3">Three</option>
    <option value="4">Four</option>
    <option value="5">Five</option>
  </select>
  <pre>{{ $data | json }}</pre>
  <div id="log">

  </div>
</div>
Flashboard answered 17/8, 2015 at 21:34 Comment(0)
C
2

This solution works for the Chosen plugin, but you can do the same thing with Select2 to make it work:

http://jsfiddle.net/simplesmiler/qfy6s9Lj/8/

Vue.directive('chosen', {
    twoWay: true, // note the two-way binding
    bind: function () {
        $(this.el)
            .chosen({
                inherit_select_classes: true,
                width: '30%',
                disable_search_threshold: 999
            })
            .change(function(ev) {
                // two-way set
                this.set(this.el.value);
            }.bind(this));
    },
    update: function(nv, ov) {
        // note that we have to notify chosen about update
        $(this.el).trigger("chosen:updated");
    }
});

var vm = new Vue({
  data: {
      city: 'Toronto',
      cities: [{text: 'Toronto', value: 'Toronto'}, 
               {text: 'Orleans', value: 'Orleans'}]
  }
}).$mount("#search-results");
Crudden answered 24/7, 2015 at 21:13 Comment(3)
While this probably works, the question is asking about Select2 and there is enough of a difference between Select2 and Chosen where it's not obvious what changes need to be made.Wether
It's easy to see what changes need to be made. Consider the following: .chosen({ inherit_select_classes: true, width: '30%', disable_search_threshold: 999 }) These are parameters to Chosen. Just replace those with the parameters to Select2. The only other thing to replace is the line $(this.el).trigger("chosen:updated");, which must be replaced with the code to notify Select2 of an update.Crudden
This is a Select2 question, not Chosen. What changes are required in this code to make it work with Select2?Wether
T
0

I made a plugin for select2 a few days ago.

https://github.com/halupi/vue-select2

Hope it helps!

Tymbal answered 25/7, 2015 at 0:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.