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.