Create a gist now

Instantly share code, notes, and snippets.

Embed
ko_selectize.js ; Full details and demo here - http://motorscript.com/selectize-js-binding-knockout-js/
var inject_binding = function (allBindings, key, value) {
//https://github.com/knockout/knockout/pull/932#issuecomment-26547528
return {
has: function (bindingKey) {
return (bindingKey == key) || allBindings.has(bindingKey);
},
get: function (bindingKey) {
var binding = allBindings.get(bindingKey);
if (bindingKey == key) {
binding = binding ? [].concat(binding, value) : value;
}
return binding;
}
};
}
ko.bindingHandlers.selectize = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
if (!allBindingsAccessor.has('optionsText'))
allBindingsAccessor = inject_binding(allBindingsAccessor, 'optionsText', 'name');
if (!allBindingsAccessor.has('optionsValue'))
allBindingsAccessor = inject_binding(allBindingsAccessor, 'optionsValue', 'id');
if (typeof allBindingsAccessor.get('optionsCaption') == 'undefined')
allBindingsAccessor = inject_binding(allBindingsAccessor, 'optionsCaption', 'Choose...');
ko.bindingHandlers.options.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
var options = {
valueField: allBindingsAccessor.get('optionsValue'),
labelField: allBindingsAccessor.get('optionsText'),
searchField: allBindingsAccessor.get('optionsText')
}
if (allBindingsAccessor.has('options')) {
var passed_options = allBindingsAccessor.get('options')
for (var attr_name in passed_options) {
options[attr_name] = passed_options[attr_name];
}
}
var $select = $(element).selectize(options)[0].selectize;
if (typeof allBindingsAccessor.get('value') == 'function') {
$select.addItem(allBindingsAccessor.get('value')());
allBindingsAccessor.get('value').subscribe(function (new_val) {
$select.addItem(new_val);
})
}
if (typeof allBindingsAccessor.get('selectedOptions') == 'function') {
allBindingsAccessor.get('selectedOptions').subscribe(function (new_val) {
// Removing items which are not in new value
var values = $select.getValue();
var items_to_remove = [];
for (var k in values) {
if (new_val.indexOf(values[k]) == -1) {
items_to_remove.push(values[k]);
}
}
for (var k in items_to_remove) {
$select.removeItem(items_to_remove[k]);
}
for (var k in new_val) {
$select.addItem(new_val[k]);
}
});
var selected = allBindingsAccessor.get('selectedOptions')();
for (var k in selected) {
$select.addItem(selected[k]);
}
}
if (typeof init_selectize == 'function') {
init_selectize($select);
}
if (typeof valueAccessor().subscribe == 'function') {
valueAccessor().subscribe(function (changes) {
// To avoid having duplicate keys, all delete operations will go first
var addedItems = new Array();
changes.forEach(function (change) {
switch (change.status) {
case 'added':
addedItems.push(change.value);
break;
case 'deleted':
var itemId = change.value[options.valueField];
if (itemId != null) $select.removeOption(itemId);
}
});
addedItems.forEach(function (item) {
$select.addOption(item);
});
}, null, "arrayChange");
}
},
update: function (element, valueAccessor, allBindingsAccessor) {
if (allBindingsAccessor.has('object')) {
var optionsValue = allBindingsAccessor.get('optionsValue') || 'id';
var value_accessor = valueAccessor();
var selected_obj = $.grep(value_accessor(), function (i) {
if (typeof i[optionsValue] == 'function')
var id = i[optionsValue]
else
var id = i[optionsValue]
return id == allBindingsAccessor.get('value')();
})[0];
if (selected_obj) {
allBindingsAccessor.get('object')(selected_obj);
}
}
}
}
<h3>1. Using selectize with plain select tag, with values built in view.</h3>
<select data-bind="selectize: {}">
<option value="1">Val 1</option>
<option value="2">Val 2</option>
</select>
<h3>2. Using values from observable array.</h3>
<select data-bind="selectize: items, value: item_id"></select>
<h3>3. Getting selected item as an object</h3>
<select data-bind="selectize: items, value: my_item_id, object: my_item"></select>
<h3>4. Using with multiselect</h3>
<select data-bind="selectize: items, selectedOptions: selected_items" multiple></select>
<h3>5. Passing additional options</h3>
<select data-bind="selectize: items, selectedOptions: selected_items2, options: {plugins: ['remove_button']}" multiple></select>
$(document).ready(function(){
ko.applyBindings(new TestVM(););
});
function TestVM(){
var self = this;
self.items = ko.observableArray([
{'id': 1, 'name': 'One'},
{'id': 2, 'name': 'Two'}
]);
self.item_id = ko.observable();
self.my_item_id = ko.observable();
self.my_item = ko.observable();
self.selected_items = ko.observableArray([1]);
self.selected_items2 = ko.observableArray();
}
@jasonhjohnson

This comment has been minimized.

Show comment
Hide comment
@jasonhjohnson

jasonhjohnson Jan 31, 2014

Are there any specific requirements to using this? I tried implementing this with the latest version of selectize and knockout but it's not working. It seems like selecting an item from the selectize box does not trigger a change.

Are there any specific requirements to using this? I tried implementing this with the latest version of selectize and knockout but it's not working. It seems like selecting an item from the selectize box does not trigger a change.

@xtranophilist

This comment has been minimized.

Show comment
Hide comment
@xtranophilist

xtranophilist Feb 5, 2014

I've updated the binding for KO 3.0. See this fiddle: http://jsfiddle.net/xtranophilist/hDefE/5/
More here: http://motorscript.com/selectize-js-binding-knockout-js/

Owner

xtranophilist commented Feb 5, 2014

I've updated the binding for KO 3.0. See this fiddle: http://jsfiddle.net/xtranophilist/hDefE/5/
More here: http://motorscript.com/selectize-js-binding-knockout-js/

@jasonhjohnson

This comment has been minimized.

Show comment
Hide comment
@jasonhjohnson

jasonhjohnson Feb 11, 2014

That worked like a charm! Thanks!

That worked like a charm! Thanks!

@jasonhjohnson

This comment has been minimized.

Show comment
Hide comment
@jasonhjohnson

jasonhjohnson Feb 17, 2014

It seems like it only works the first time I load the page. When I refresh, change the value of the selectize drop down (select an option), it doesn't update the observable. Occasionally it will show up. It's bizarre. Would it help if I provided you with the associated code?

-J

It seems like it only works the first time I load the page. When I refresh, change the value of the selectize drop down (select an option), it doesn't update the observable. Occasionally it will show up. It's bizarre. Would it help if I provided you with the associated code?

-J

@xtranophilist

This comment has been minimized.

Show comment
Hide comment
@xtranophilist

xtranophilist Jun 29, 2014

@jasonhjohnson sorry for the late reply.
Did you solve the problem? Can you please post the associated code?

Owner

xtranophilist commented Jun 29, 2014

@jasonhjohnson sorry for the late reply.
Did you solve the problem? Can you please post the associated code?

@MrOpperman

This comment has been minimized.

Show comment
Hide comment
@MrOpperman

MrOpperman Jul 15, 2014

@xtranophilist this doesn't seem to work with dynamically loading data? Am I wrong? Please let me know.

@xtranophilist this doesn't seem to work with dynamically loading data? Am I wrong? Please let me know.

@MrTrick

This comment has been minimized.

Show comment
Hide comment
@MrTrick

MrTrick Jul 31, 2014

@xtranophilist What is the init_selectize variable? - it's not defined anywhere.

Would you consider putting this code into a proper project?

MrTrick commented Jul 31, 2014

@xtranophilist What is the init_selectize variable? - it's not defined anywhere.

Would you consider putting this code into a proper project?

@dave600b

This comment has been minimized.

Show comment
Hide comment
@dave600b

dave600b Jul 31, 2014

Hi,
When using an OptionsValue parameter the object is not set correctly.
The update needs i.id replacing with i[allBindingsAccessor().optionsValue]

or

        var optionsValue = allBindingsAccessor().optionsValue;

        var selected_obj = $.grep(value_accessor(), function (i) {
            if (typeof i[optionsValue] == 'function')
                var id = i[optionsValue]()
            else
                var id = i[optionsValue]

            return id == allBindingsAccessor.get('value')();
        })[0];

Demoed in a fiddle http://jsfiddle.net/d600burton/6j7a5/2/

Thanks for the great binding!

Hi,
When using an OptionsValue parameter the object is not set correctly.
The update needs i.id replacing with i[allBindingsAccessor().optionsValue]

or

        var optionsValue = allBindingsAccessor().optionsValue;

        var selected_obj = $.grep(value_accessor(), function (i) {
            if (typeof i[optionsValue] == 'function')
                var id = i[optionsValue]()
            else
                var id = i[optionsValue]

            return id == allBindingsAccessor.get('value')();
        })[0];

Demoed in a fiddle http://jsfiddle.net/d600burton/6j7a5/2/

Thanks for the great binding!

@xtranophilist

This comment has been minimized.

Show comment
Hide comment
@xtranophilist

xtranophilist Nov 12, 2014

Thanks everybody. I've updated the binding.

@MrOpperman
This should now work with dynamically loaded data. I'd appreciate if you checked and let me know.

@MrTrick
init_selectize is a custom function where you can put your business logic that needs to be triggered when the selectize is initiated. I've used it to append 'Add New Object' at the bottom of the drop down.

@dave600b
Thank you for the fix and the love. I've incorporated it.

  • X
Owner

xtranophilist commented Nov 12, 2014

Thanks everybody. I've updated the binding.

@MrOpperman
This should now work with dynamically loaded data. I'd appreciate if you checked and let me know.

@MrTrick
init_selectize is a custom function where you can put your business logic that needs to be triggered when the selectize is initiated. I've used it to append 'Add New Object' at the bottom of the drop down.

@dave600b
Thank you for the fix and the love. I've incorporated it.

  • X
@bmxpert1

This comment has been minimized.

Show comment
Hide comment
@bmxpert1

bmxpert1 Mar 18, 2015

@xtranophilist
I think line 110 was supposed to end up calling the function if it is one. Just noticed that.

I performed the change in my fork for reference.
https://gist.github.com/bmxpert1/979eb622d61341969698/revisions

Thanks for the nice binding, very helpful!

@xtranophilist
I think line 110 was supposed to end up calling the function if it is one. Just noticed that.

I performed the change in my fork for reference.
https://gist.github.com/bmxpert1/979eb622d61341969698/revisions

Thanks for the nice binding, very helpful!

@stechnique

This comment has been minimized.

Show comment
Hide comment
@stechnique

stechnique Mar 19, 2015

Hi, I love your binding, but I just noticed a problem I'm having with it in a specific use case. I have this code

<select data-bind="options: $root.availablePlans, optionsValue: 'title', optionsText: 'title', value: ratePlan, options: { dropdownParent: 'body', create: true, closeAfterSelect: true, createOnBlur: true }"></select>

This works great if the ratePlan observable is blank at first. As soon as I select something on the selectize input the model is updated. But if ratePlan was set in the beginning, I see the proper option selected in the input, but the KO model observable is updated with "undefined". So when I submit the form I lose the information. I looked at the source and could not find a reason for this. If I remove the value binding on the component then it stays with the value it had (it is not overwritten to undefined). If I replace the selectize binding with a normal options binding, it works well.

Anyone else run into this?

Hi, I love your binding, but I just noticed a problem I'm having with it in a specific use case. I have this code

<select data-bind="options: $root.availablePlans, optionsValue: 'title', optionsText: 'title', value: ratePlan, options: { dropdownParent: 'body', create: true, closeAfterSelect: true, createOnBlur: true }"></select>

This works great if the ratePlan observable is blank at first. As soon as I select something on the selectize input the model is updated. But if ratePlan was set in the beginning, I see the proper option selected in the input, but the KO model observable is updated with "undefined". So when I submit the form I lose the information. I looked at the source and could not find a reason for this. If I remove the value binding on the component then it stays with the value it had (it is not overwritten to undefined). If I replace the selectize binding with a normal options binding, it works well.

Anyone else run into this?

@xtranophilist

This comment has been minimized.

Show comment
Hide comment
@xtranophilist

xtranophilist Jun 23, 2015

@stechnique
You are using options binding and not selectize binding?

Owner

xtranophilist commented Jun 23, 2015

@stechnique
You are using options binding and not selectize binding?

@jonesy827

This comment has been minimized.

Show comment
Hide comment
@jonesy827

jonesy827 Aug 18, 2015

@xtranophilist

<select data-bind="selectize: $root.Exercises, value: ExerciseID, optionsValue: function(item){return item.ExerciseID()}, optionsText: function(item){return item.ExerciseName();},  opt: {create: $root.CreateExercise}"></select>

The list does not seem to be updated when the associated observable array has items added. However, if I create a new instance of this same binding it has the updated items. I presume it's a problem with the update function, but I'm not exactly sure what needs to happen to get it working properly.

EDIT: I should note that I am simply pushing items into the observable array.

@xtranophilist

<select data-bind="selectize: $root.Exercises, value: ExerciseID, optionsValue: function(item){return item.ExerciseID()}, optionsText: function(item){return item.ExerciseName();},  opt: {create: $root.CreateExercise}"></select>

The list does not seem to be updated when the associated observable array has items added. However, if I create a new instance of this same binding it has the updated items. I presume it's a problem with the update function, but I'm not exactly sure what needs to happen to get it working properly.

EDIT: I should note that I am simply pushing items into the observable array.

@MrMamen

This comment has been minimized.

Show comment
Hide comment
@MrMamen

MrMamen Sep 23, 2015

The destroy method does not revert the item properly. For example tabIndex is left at -1. See destroy method here for missing parameters:
https://github.com/brianreavis/selectize.js/blob/master/src/selectize.js

MrMamen commented Sep 23, 2015

The destroy method does not revert the item properly. For example tabIndex is left at -1. See destroy method here for missing parameters:
https://github.com/brianreavis/selectize.js/blob/master/src/selectize.js

@tejovanthn

This comment has been minimized.

Show comment
Hide comment
@tejovanthn

tejovanthn Dec 15, 2015

Does tagging work with this script? The first two examples here: http://brianreavis.github.io/selectize.js/

Does tagging work with this script? The first two examples here: http://brianreavis.github.io/selectize.js/

@firrae

This comment has been minimized.

Show comment
Hide comment
@firrae

firrae Jan 12, 2016

Is this binding only working in Knockout 3.0+? I'm working on an old knockout app that's stuck on 2.2.1 and this is the best option to use, but if I have to update Knockout to 3+ it may not be worth it.

firrae commented Jan 12, 2016

Is this binding only working in Knockout 3.0+? I'm working on an old knockout app that's stuck on 2.2.1 and this is the best option to use, but if I have to update Knockout to 3+ it may not be worth it.

@mrshawn191

This comment has been minimized.

Show comment
Hide comment
@mrshawn191

mrshawn191 Jan 4, 2018

I am having an issue when using webpack 3.10.0 where ko.subscribe is no longer triggered in this binding... any ideas why?

I am having an issue when using webpack 3.10.0 where ko.subscribe is no longer triggered in this binding... any ideas why?

@Lislex

This comment has been minimized.

Show comment
Hide comment
@Lislex

Lislex Feb 4, 2018

How would this work with option groups?

Lislex commented Feb 4, 2018

How would this work with option groups?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment