Skip to content

Instantly share code, notes, and snippets.

@lmonilsson
Created November 3, 2015 12:21
Show Gist options
  • Save lmonilsson/080a9400f376465fcabb to your computer and use it in GitHub Desktop.
Save lmonilsson/080a9400f376465fcabb to your computer and use it in GitHub Desktop.
Makes it possible to use arbitrary objects as option values for a <select> with Knockout.
(function () {
function extractOptionsValues(options, optionsValueProp) {
var optionsValues = [];
for (var i = 0; i < options.length; i++) {
var opt = ko.unwrap(options[i]);
var optValue = opt[optionsValueProp];
optionsValues.push(optValue);
}
return optionsValues;
}
function getSelectedOptionsValues(optionsValues, selectedValues) {
var selectedOptionsValues = [];
for (var i = 0; i < optionsValues.length; i++) {
var optValue = optionsValues[i];
var optValueJSON = optValue != null ? ko.mapping.toJSON(optValue) : null;
for (var j = 0; j < selectedValues.length; j++) {
var selectedValue = selectedValues[j];
var selectedValueJSON = selectedValue != null ? ko.mapping.toJSON(selectedValue) : null;
if (optValueJSON === selectedValueJSON) {
selectedOptionsValues.push(optValue);
break;
}
}
}
return selectedOptionsValues;
}
function fixOptions(element, valueAccessor, allBindingsAccessor) {
var allBindings = allBindingsAccessor();
var options = ko.unwrap(allBindings.options);
var valueProp = ko.unwrap(allBindings.optionsValue);
var optionsValues = extractOptionsValues(options, valueProp);
var selectedValueObservable = allBindings.value;
var selectedValuesObservable = allBindings.selectedOptions;
var isMultiSelect = selectedValuesObservable != null;
if (isMultiSelect) {
var selectedValues = ko.unwrap(selectedValuesObservable);
var selectedOptionsValues = getSelectedOptionsValues(optionsValues, selectedValues);
selectedValuesObservable(selectedOptionsValues);
} else {
var selectedValue = ko.unwrap(selectedValueObservable);
var selectedOptionsValues = getSelectedOptionsValues(optionsValues, [selectedValue]);
selectedValueObservable(selectedOptionsValues[0]);
}
}
// TODO: May want an option for restoring valueAllowUnset to false.
/// Makes it possible to use arbitrary objects as option values for a <select>.
/// Normally, only primitive values can be used as option values.
/// This requires setting valueAllowUnset = true.
///
/// <select data-bind="options: options,
/// optionsValue: 'value',
/// optionsText: 'text',
/// value: currentValue,
/// valueAllowUnset: true,
/// optionsObjectValues: true" />
ko.bindingHandlers.optionsObjectValues = {
init: function (element, valueAccessor, allBindingsAccessor) {
fixOptions(element, valueAccessor, allBindingsAccessor);
},
update: function (element, valueAccessor, allBindingsAccessor) {
fixOptions(element, valueAccessor, allBindingsAccessor);
},
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment