Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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();
}
@firrae
Copy link

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
Copy link

mrshawn191 commented 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?

@Lislex
Copy link

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