9

Trying to use jquery-chosen with vue, the problem is that this plugin hides the actual select that I applied v-model, so when I select a value vue doesn't recognize it as a select change event and model value is not updated.

The value of the select is being changed actually when I select something, I've inspected this with console.log to see the selected value.

http://jsfiddle.net/qfy6s9Lj/3/

I could do vm.$data.city = $('.cs-select').val(), that seems to work, But is there another option? If the value of the select was changed why vue doesn't see this?

6 Answers 6

4

@swift's answer got pretty close, but as @bertrand pointed out, it doesn't work for multiselects. I've worked something out that works with both cases: http://jsfiddle.net/seanwash/sz8s99xx/

I would have just commented but I don't have enough rep to do so.

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
                // Construct array of selected options
                var i, len, option, ref;
                var values = [];
                ref = this.el.selectedOptions;
                for (i = 0, len = ref.length; i < len; i++) {
                    option = ref[i];
                    values.push(option.value)
                }
                
                this.set(values);
                
            }.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");

Sign up to request clarification or add additional context in comments.

2 Comments

One more time... Here's an update (in coffeescript) that returns an array if the select is a multi select and a string if it's not: jsfiddle.net/seanwash/wmrkrdzr/1
I haven't tried. I've been using monterail.github.io/vue-multiselect which has been great so far.
3

I am opened for other suggestions, but for the time-being I did it this way:

html

<div id='search-results'>
    {{city}}
    <select class="cs-select" v-model='city'>
        <option value="Toronto">Toronto</option>
        <option value="Orleans">Orleans</option>
    </select>
</div>

js

window.vm = new Vue({
  el: '#search-results',
  data: {
    city: 'Toronto',
  }
})

$('.cs-select').chosen({
    inherit_select_classes: true,
    width: '30%'
}).change( function() {
    vm.$data.city = $('.cs-select').val()
})

Comments

3

Update: Be advised this doesn't work from within a v-for loop. A related question that deals with that is available here.

Going off of @kaktuspalme's solution, and with help from my friend Joe Fleming, I came up with a solution that works with Vue 2 and allows single and multiple selections:

Vue.directive('chosen', {
    inserted: function(el, binding, vnode) {
        jQuery(el).chosen().change(function(event, change) {
            if (Array.isArray(binding.value)) {
                var selected = binding.value;
                if (change.hasOwnProperty('selected')) {
                    selected.push(change.selected);
                } else {
                    selected.splice(selected.indexOf(change.deselected), 1);
                }
            } else {
                var keys = binding.expression.split('.');
                var pointer = vnode.context;
                while (keys.length > 1)
                    pointer = pointer[keys.shift()];
                pointer[keys[0]] = change.selected;
            }
        });
    },
    componentUpdated: function(el, binding) {
        jQuery(el).trigger("chosen:updated");
    }
});

Use it like this:

<select v-model="mymodel" v-chosen="mymodel">...</select>

It works with multiple="multiple" and even with nested state, e.g.:

<select v-model="nested.mymodel" v-chosen="nested.mymodel">...</select>

See the fiddle here: https://jsfiddle.net/tylercollier/bvvvgyp0/5/

Comments

2

Answer: http://jsfiddle.net/qfy6s9Lj/5/

<div id='search-results'>
    Vue model value <br>
    {{city}}
    <hr>
    Select value:
    <select class="cs-select" v-chosen>
       <option value="Toronto">Toronto</option>
       <option value="Orleans">Orleans</option>
    </select>
</div>

Vue.directive('chosen', {
    bind: function () {
        var vm = this.vm;
        this.el.options = vm.cities;
        this.el.value = vm.city;       

        $(this.el).chosen({
            inherit_select_classes: true,
            width: '30%',
            disable_search_threshold: 999})
        .change( function() {
             vm.city = this.el.value;
         }.bind(this)
      );
    }
});

var vm = new Vue({
  data: {
      city: 'Toronto',
      cities: ['Toronto', 'Orleans']
  }
}).$mount("#search-results");

UPDATE: an even better solution (thanks to simplesmiler): http://jsfiddle.net/simplesmiler/qfy6s9Lj/8/

1 Comment

it seems that this doesn't work with select tag that has an attribute of multiple (multiselect).
2

I made an update for vue2.

Vue.directive('chosen', {
    selected: null,
    inserted: function (el, binding) {
        selected = binding.value;
        $(el).chosen().change(function(event, change) {
            if(change.hasOwnProperty('selected')) {
                selected.push(change.selected);
            } else {
                selected.splice(selected.indexOf(change.deselected), 1);
            }
        });
    },
    componentUpdated: function(el, binding) {
        selected = binding.value;           
        $(el).trigger("chosen:updated");
    }
});

var vm = new Vue({
   el: '#app',
   data: {
      selected: [],
      cities: [{id: 1, value: "Toronto"}, {id: 2, value: "Orleans"}, {id: 3, value: "Bern"}]
   }
});

See: https://jsfiddle.net/kaktuspalme/zenksm2b/

1 Comment

This doesn't seem to work for non-multiple select elements. Also, what is the selected: null? That seems superfluous? And where you write selected = binding.value, aren't you setting a global variable?
0

Code taken from @kaktuspalme answer. It works with non-multiple elements now and only for non-multiple.

 Vue.directive('chosensingle', {

inserted: function (el, binding) {
    var selected = binding.value;

    $(el).chosen().change(function(event, change) {

        if(change.hasOwnProperty('selected')) {
            selected.value = change.selected;                
        } else {
            selected.value  ='';
        }
    });
},
componentUpdated: function(el, binding) {

    $(el).trigger("chosen:updated");
}
});

Comments from @Tyler Collier are taken into account

But be carefully,property you use in v-model should be defined as array , e.g. applicantId: [] otherwise it doesn't work

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.