-
-
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"] | |
} | |
}); |
@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>
@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