-
-
Save DrSammyD/3ae055ca1280ccd9a4ae to your computer and use it in GitHub Desktop.
(function (factory) { | |
'use strict'; | |
if (typeof define === 'function' && define.amd) { | |
define(['knockout','jquery','selectize'], factory); | |
} else { | |
var selConstructor = (typeof selectize != "undefined")?selectize:$('<select>').selectize().data('selectize').constructor; | |
factory(ko,$,selConstructor); | |
} | |
})(function (ko,$,selectize) { | |
var _key= null; | |
for(_key in ko.bindingHandlers.options){ | |
if(typeof ko.bindingHandlers.options[_key] =='string' && ko.bindingHandlers.options[_key].match('__ko__')) | |
break; | |
} | |
var inject_binding = function (allBindings, key, value) { | |
//https://github.com/knockout/knockout/pull/932#issuecomment-26547528 | |
var has = allBindings.has; | |
var get = allBindings.get; | |
return { | |
has: function (bindingKey) { | |
return (bindingKey == key) || has.call(allBindings,bindingKey); | |
}, | |
get: function (bindingKey) { | |
var binding = get.call(allBindings,bindingKey); | |
if (bindingKey == key) { | |
binding = binding ? [].concat(binding, value) : value; | |
} | |
return binding; | |
} | |
}; | |
} | |
var setOptionNodeSelectionState =function (optionNode, isSelected) { | |
optionNode.selected = isSelected; | |
} | |
selectize.prototype.updateOriginalInput=function(){ | |
var i, n, options, self = this; | |
if (self.$input[0].tagName.toLowerCase() === 'select') { | |
options = []; | |
ko.utils.arrayForEach(self.$input.get(0).getElementsByTagName("option"),function(node){ | |
var isSelected = self.items.indexOf(node[ko.bindingHandlers.options[_key].slice(1)]||node['value']) !=-1 | |
setOptionNodeSelectionState(node, isSelected); | |
}) | |
} else { | |
self.$input.val(self.getValue()); | |
} | |
self.$input.trigger('propertychange'); | |
if (self.isSetup) { | |
self.trigger('change', self.$input.val()); | |
} | |
} | |
selectize.prototype.destroy=function(){ | |
var self = this; | |
var eventNS = self.eventNS; | |
self.trigger('destroy'); | |
self.off(); | |
self.$wrapper.remove(); | |
self.$dropdown.remove(); | |
$(window).off(eventNS); | |
$(document).off(eventNS); | |
$(document.body).off(eventNS); | |
delete self.$input[0].selectize; | |
} | |
ko.bindingHandlers.selectizeOptions={ | |
init:function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
var $el= $(element); | |
if(allBindingsAccessor.get('selectizeMultiple')) | |
$(element).prop('multiple',true); | |
$.extend(allBindingsAccessor, inject_binding(allBindingsAccessor,'optionsAfterRender',function(el){ | |
$(el).attr('value', el[ko.bindingHandlers.options[_key].slice(1)]||el['value']) | |
})); | |
var ret= ko.bindingHandlers.options.init(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
$el.selectize({ | |
placeholder: ko.unwrap(allBindingsAccessor.get('optionsCaption')) | |
}); | |
ko.utils.domNodeDisposal.addDisposeCallback(element, function() { | |
$el.data('selectize').destroy(); | |
}); | |
return ret; | |
}, | |
update:function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
var ret= ko.bindingHandlers.options.update(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
var $el= $(element); | |
$el.data('selectize').destroy(); | |
var $chi=$el.children(); | |
$el.selectize({ | |
placeholder: ko.unwrap(allBindingsAccessor.get('optionsCaption')) | |
}); | |
$el.append($chi); | |
ret= ko.bindingHandlers.options.update(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
return ret; | |
} | |
} | |
ko.bindingHandlers.selectizeCaption = { | |
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
ko.bindingHandlers.optionsCaption.update(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
$(element).data('selectize').settings.placeholder= ko.unwrap(valueAccessor()); | |
$(element).data('selectize').updatePlaceholder(); | |
} | |
} | |
ko.bindingHandlers.selectize = { | |
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
ko.bindingHandlers.value.init(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext) | |
}, | |
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
ko.unwrap(valueAccessor()); | |
ko.bindingHandlers.value.update(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
$el=$(element); | |
$el.data('selectize').setValue( | |
$el.find(":selected") | |
.map(function(i,el){ | |
return el[ko.bindingHandlers.options[_key].slice(1)]||el['value'] | |
}).get()[0] | |
); | |
}, | |
after: ["selectizeOptions"] | |
} | |
ko.bindingHandlers.selectizeMultiple = { | |
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
$(element).prop('multiple',true); | |
ko.bindingHandlers.selectedOptions.init(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
}, | |
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { | |
ko.bindingHandlers.selectedOptions.update(element,valueAccessor, allBindingsAccessor, viewModel, bindingContext); | |
$el=$(element); | |
$el.data('selectize').setValue( | |
$el.find(":selected") | |
.map(function(i,el){ | |
return el[ko.bindingHandlers.options[_key].slice(1)]||el['value'] | |
}).get() | |
); | |
}, | |
after: ["selectizeOptions"] | |
} | |
}); |
Do you have any usage samples, please? Thank you!
Can u give more example plz ?
How can i use a object like with optionValue and optionText ?
@melck in exactly the same way you would normally use them
hi @DrSammyD!
I'm using your plugin to integrate selectize with knockoutjs and it's works perfectly!
I've a suggestion: create a binding option called selectizeOptions with all selectize support options and use it when you call $(element).selectize({ ...})... so the plugin will be more extended!
Hi @DrSammyD.
First of all, thanks for this awesome binding!
I have a question regarding the use of this binding together with the value binding provided by knockout.
This jsfiddle ( http://jsfiddle.net/Lgs2fx90/1/ ) shows a default knockout binding on a select, which dynamically adds items when the button is pushed. The selected value is outputted next to the button.
If I then add your binding, and update my markup to use selectizeOptions instead of options, I only get an update to my value property on the very first time I add an item. (example: http://jsfiddle.net/5pxa5rft/)
Do you have an explanation for why this is happening or is perhaps my expectation to see the values updated wrong?
Thanks again!
// Shane
@ShaneCoufreur you need selectize
or selectizeMultiple
and selectizeOptions
. selectize
and selectizeMultiple
replace the value binding.
here's a working jsfiddle of what you're trying to do
http://jsfiddle.net/fm19zxj8/16/
@DrSammyD Thanks for the response! I didn't know selectize replaced the value binding.
What I'm seeing now is that if i put a non-integer value in the optionValue property, it stops working.
http://jsfiddle.net/fm19zxj8/17/ (The new values work, because they're integers, the values in model upon creation don't, because they're string. The binding outputs the value for the strings, and something different for the int ones
@ShaneCoufreur yes, well that would be because the binding is broken 😀
Fixed
http://jsfiddle.net/fm19zxj8/23/
I think it has to do with the options binding not using the #__ko__###
for a lookup of option values if the value is a string instead of an int, which doesn't make any sense to me, but what ever.
Hi @DrSammyD,
i think there is an error in your last commit.
Infact, in your last fiddle you wrote this line in selectizeOptions init binding:
$.extend(allBindingsAccessor, inject_binding(allBindingsAccessor,'optionsAfterRender',function(el){
$(el).attr('value', el[ko.bindingHandlers.options[_key].slice(1)]||el['value'])
}));
but in your last git you committed this:
$.extend(allBindingsAccessor, inject_binding(allBindingsAccessor,'optionsAfterRender',function(el){
$el.attr('value', el[ko.bindingHandlers.options[_key].slice(1)]||el['value'])
}));
and the options selection doesn't work.
Daniele
@lelelic Thanks
Hi DrSammyD :)
I think there is an issue with the subscribe event.. How you can see in this fiddle (http://jsfiddle.net/p3y05ukc/9/), ko-selectize is firing twice subscribe event while the "classic" option of knockout once. I've tried to investigate the code but i didn't found the codeline that generate the trouble..
Thanks,
Daniele
Can I please see an example that uses selectizeMultiple? I would like to have an observable that contains the currently selected options.
Excellent work Dr Sammy D! This is exactly what I needed!
@ehartford: Take a look at this: http://jsfiddle.net/fm19zxj8/25/
@DrSammyD
I'm not sure if you are working on this still or not but I ran into an issue which I think would be easy to solve (for you).
The call to $(element).selectize({ ... });' is only made in the
selectizeOptions` bindingHandler, which cannot be used if the options are hard-coded into the html. It might be a good idea to check if the element has been initialized and if not, go ahead and do so in each bindingHandler. Thoughts?
Hi @DrSammyD,
I've a simple question: how can I pre-select an option if I use optionValue and OptionText?
In this fiddle I try to get it but without results: http://jsfiddle.net/bqgd81jz/1/ . If you notice the value observable is initialized with 3.
Thanks in advance.
Daniele
@DrSammyD do you see a possibility to hand over selectize constructor options? For example plugins
or render: {option: ...}
would be very handy and it feels weird to put them in the code directly.
Hey @krnlde looks at my gist https://gist.github.com/lelelic/114a286649438b6ef365. I've added the option "selectizeSettings" where you can specify all the options of selectize constructor.
For example:
<select name="sel1" class="form-control" data-bind='selectize: values, selectizeOptions: myValues, optionsText: "Description", optionsValue: "Id", selectizeSettings: {onDelete: function() { return false }}'></select>
nice