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>
Vue is also perfectly capable of powering sophisticated Single-Page Applications in combination with modern tooling and supporting libraries. The v-model directive makes two-way binding between a form input and app state very easy to implement.
The v-bind directive is a Vuejs directive used to bind one or more attributes, or a component prop to an element. If that attribute is binded to our data defined in Vuejs instance then dynamically changes can be observed as data changes.
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>
...
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>
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With