Reputation: 196
I have a setup, where I populate a select with options based on a observableArray. This array contains objects with more properties than just an id and a name. I want to be able to use the full javascript object as the selected value.
The data is like this:
this.optionData = ko.observableArray([
{id: 1, name: "One", param: true},
{id: 2, name: "Two", param: true},
{id: 3, name: "Three", param: true},
]);
And with standard bindings in knockout its nice and easy
<select data-bind="
options: optionData,
optionsText: 'name',
optionsCaption: 'Please select',
value: selectedOption">
</select>
However, I want to style my selects, and add more functionality to them. I use select2 for this. I've come up with the following custom binding, and this works fine for simple bindings with both a optionsText and optionsValue - but it does not work for options bindings without the optionsValue (ie. when using objects as a value).
ko.bindingHandlers.select2 = {
init: function (el, valueAccessor, allBindingsAccessor, viewModel) {
ko.utils.domNodeDisposal.addDisposeCallback(el, function () {
$(el).select2('destroy');
});
var allBindings = allBindingsAccessor(),
select2 = ko.utils.unwrapObservable(valueAccessor());
$(el).select2(select2);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var selectedOptions = ko.unwrap(allBindingsAccessor.get("selectedOptions")),
val = ko.unwrap(allBindingsAccessor.get("value")),
options = ko.unwrap(allBindingsAccessor.get("options"));
if ($(element).prop('multiple')) {
$(element).select2('val', selectedOptions, true);
}
else {
$(element).select2("val", val);
}
$(element).trigger('change');
}
};
My question is this, what do I need to update in order for my custom binding to work as the default knockout options binding?
I've made this fiddle to demonstrate the issue: http://jsfiddle.net/SuneRadich/LdF45/1/
Upvotes: 1
Views: 971
Reputation: 2202
My example might help with using optionsAfterRender to get the objects.
<select id="selectArticles" multiple
data-bind="options: availableArticles, selectedOptions: selectedArticles,
optionsText: function(item){return item.title},
optionsAfterRender: function(option, item){option.value = item}">
</select>
If necessary I can change it to single select.
Upvotes: 1
Reputation: 19882
You can use optionAfterRender
property for adding more functionality to your select
.
Consider this example
<select
data-bind="
options: options,
value : selectedOption,
optionsText: 'Name',
optionsAfterRender: $root.setTitle
"
></select><br />
<button data-bind="click: showSelectedOptions">Show selection</button>
function Option(id, name){
var self = this;
self.Id = id;
self.Name = name;
}
function ViewModel(){
var self = this;
self.options = ko.observableArray([
new Option(0, "NormalText"),
new Option(1, "AnotherText"),
new Option(2, "WaaaaaaaaaaaaaaaayTooLongText")
]);
self.selectedOption = ko.observable();
self.showSelectedOptions = function(){
console.log(self.selectedOption());
}
self.setTitle = function(option, item) {
option.title = item.Name
// other properties
}
}
ko.applyBindings(new ViewModel());
Make sure you have version 3.1.0
Upvotes: 1