Search code examples
javascriptlaravelvuejs2jquery-select2

Using select2 with vuejs directive, data from html


I have tried to create a vuejs2 directive, which would pick the already rendered select and wrap it into select2. This part is working but doesn't pick the selected value:

Vue.directive('select', {
    inserted: function (el) {

        $(el).select2({
            matcher: modelMatcher,
            minimumResultsForSearch: 6,
            dropdownAutoWidth: true,
            width: 'auto'
        });

    }
});

Any ideas how to do this? This probably worked with vuejs 1:

https://gist.github.com/themsaid/c0548e19f247b832ac4f

but not working any more.


Solution

  • The issue is select2, when changed, throws a jQuery.Event Object, and Vue only reacts to regular JavaScript events.

    So the solution is to, after initializing select2, listen to the change jQuery.Event it emits and emit a change CustomEvent as well, so Vue picks it up.

    When Vue picks the change CustomEvent, it will update the v-model.

    Demo below.

    Vue.directive('select', {
      inserted: function(el) {
        var self = this;
        $(el).select2({
          //matcher: modelMatcher,
          //minimumResultsForSearch: 6,
          //dropdownAutoWidth: true,
          width: 'auto'
        }).on('change', function(e) {
          if (e.detail === "vue-directive") {
            return; // prevent stack overflow (i.e. listening to the event we threw ourselves)
          }
          // throw regular change (non jQuery) event, so vue reacts
          el.dispatchEvent(new CustomEvent("change", {
            detail: "vue-directive"
          }));
          return false;
        })
      }
    });
    new Vue({
      el: '#app',
      data: {
        states: ["AL", "AK", "AZ"],
        selectedState: "AK",
      }
    })
    <script src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app">
      <select v-model="selectedState" v-select>
        <option v-for="state in states" :value="state">{{ state }}</option>
      </select>
      <p>Selected State: {{ selectedState }}</p>
    </div>

    Note that's just one way of doing it, there's a great variety of possibilities, making use of Vue's Custom Directives Hook Functions. Also note that the example I show above is sligthly simpler than the gist you provided, as it does not handle the unbind hook, for instance. The implementation should be straightforward, OTOH.