Select2 on change event is not working in Vuejs

14,026

Solution 1

To get this to work with a directive, we need to understand how v-model works. From the docs:

<input v-model="something">

is just syntactic sugar for:

<input v-bind:value="something" v-on:input="something = $event.target.value">

In the case of a select element, v-model will listen for the change event (not input). So, if the directive dispatches a change event when the element changes, then v-model will work as expected.

Here is an updated version of your code (works in Vue 2):

Vue.directive('select', {
  twoWay: true,
  bind: function (el, binding, vnode) {
    $(el).select2().on("select2:select", (e) => {
      // v-model looks for
      //  - an event named "change"
      //  - a value with property path "$event.target.value"
      el.dispatchEvent(new Event('change', { target: e.target }));
    });
  },
  componentUpdated: function(el, me) {
    // update the selection if the value is changed externally
    $(el).trigger("change");
  }
});
var app = new Vue({
  el: '#app',
  data: {
    supplier_id: "niklesh"
  },
})
$('#supplier_id').select2({});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.css">
<div id="app">
  {{ supplier_id }}

  <select id="supplier_id" class='form-control' v-model='supplier_id' v-select='supplier_id'>
    <option value="atul">Atul</option>
    <option value="niklesh">Niklesh</option>
    <option value="sachin">Sachin</option>
  </select>

</div>

And here's a version that works in Vue 3 (custom directives have different syntax, linked here):

var app = Vue.createApp({
  data: function() { 
    return {
      supplier_id: "niklesh"
    }
  }
})

app.directive('select', {
  beforeMount: function (el, binding, vnode) {
    $(el).select2().on("select2:select", (e) => {
      // v-model looks for
      //  - an event named "change"
      //  - a value with property path "$event.target.value"
      el.dispatchEvent(new Event('change', { target: e.target }));
    });
  },
    updated: function(el) {
    // update the selection if the value is changed externally
    $(el).trigger("change");
  }
});

app.mount('#app');

$('#supplier_id').select2({});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.css">
<div id="app">
  {{ supplier_id }}

  <select id="supplier_id" class='form-control' v-model='supplier_id' v-select='supplier_id'>
    <option value="atul">Atul</option>
    <option value="niklesh">Niklesh</option>
    <option value="sachin">Sachin</option>
  </select>

</div>

Solution 2

By assigning select2 value to vuejs data I am able to fix this problem. I didn't use custom directive here.

var app = new Vue({
  el: '#app',
  data: {
    supplier_id: "niklesh"
  },
  filters: {
    capitalize: function (value) {
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
});

$('#supplier_id').on("change",function(){
    app.supplier_id = $(this).val();
    console.log('Name : '+$(this).val());
});

$('#supplier_id').select2({});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.css">
<div id="app">
  Name : {{ supplier_id | capitalize }}
<select id="supplier_id" class='form-control' v-model='supplier_id'>
    <option value="atul">Atul</option>
    <option value="niklesh">Niklesh</option>
    <option value="sachin">Sachin</option>
</select>

</div>

Please comment if this is not good way or any better solution you suggest.

Solution 3

<select v-model="selected">
       <option value="1">1</option>
       <option value="2">2</option>
       <option value="3">3</option>
</select>


const self = this;
$("select").change(function () {
        const val = $(this).find("option:selected").val();
        self.selected = val;
 });
Share:
14,026
Niklesh Raut
Author by

Niklesh Raut

Jo pass hai wahi khaas hai, Baki sab bakwaas hai. ✍(◔◡◔) : rishiraut16 AT gmail.com

Updated on June 05, 2022

Comments

  • Niklesh Raut
    Niklesh Raut almost 2 years

    I was working with select2 in vuejs , I found vuejs is not working with jquery select2 as vuejs is working with navite html.

    I am using this code

    Vue.directive('select', {
            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");
            }
        });
        var app = new Vue({
          el: '#app',
          data: {
            supplier_id: "niklesh"
          }
        })
        $('#supplier_id').select2({});
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.css">
    <div id="app">
      {{ supplier_id }}
    
    <select id="supplier_id" class='form-control' v-model='supplier_id' v-select='supplier_id'>
        <option value="atul">Atul</option>
        <option value="niklesh">Niklesh</option>
        <option value="sachin">Sachin</option>
    </select>
    
    </div>

    Please share your reply to handle this problem.

  • darryn.ten
    darryn.ten over 7 years
    asked AND answered 1 minute ago?
  • Niklesh Raut
    Niklesh Raut over 7 years
    @darryn.ten: This is my own answer, although its works through jquery but I would be great if I can solve this through vuejs.
  • asemahle
    asemahle over 7 years
    @Rishi: I don't think this is a bad solution, but your original idea of using a directive seems more reusable. I've added a solution showing how you could use a directive instead.
  • KevinO
    KevinO over 5 years
    This answer would be improved by providing an explanation as to why it works, and why it is a better approach than the accepted answer.
  • Patrizio Bekerle
    Patrizio Bekerle over 5 years
    Thank you for your solution! I am using a multi-select, so I also had to trigger the change event on select2:unselect, like this: $(el).select2().on("select2:select select2:unselect", (e) => {
  • Moauya Meghari
    Moauya Meghari over 3 years
    The easiest and simplest solution. Thanks.
  • e4rthdog
    e4rthdog almost 3 years
    This doen't seem to work with Vue3. Any ideas why?
  • asemahle
    asemahle almost 3 years
    @e4rthdog Directives work differently in Vue 3. I added a code snippet for Vue 3.