Created
November 12, 2013 14:34
-
-
Save Tomalak/7431769 to your computer and use it in GitHub Desktop.
A knockout.js custom binding for HTM5 <datalist> based input fields. Explanation over here. http://stackoverflow.com/a/19867498/18771
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* enables convenient creation and use of HTML5 datalist inputs | |
* - knockout.js 2.3.0+ | |
* - http://stackoverflow.com/a/19867498/18771 | |
* - http://jsfiddle.net/GJ4h4/3/ | |
*/ | |
ko.bindingHandlers.datalist = (function () { | |
function getVal(rawItem, prop) { | |
var item = ko.unwrap(rawItem); | |
return item && prop ? ko.unwrap(item[prop]) : item; | |
} | |
function findItem(options, prop, ref) { | |
return ko.utils.arrayFirst(options, function (item) { | |
return ref === getVal(item, prop); | |
}); | |
} | |
return { | |
init: function (element, valueAccessor, allBindingsAccessor) { | |
var setup = valueAccessor(), | |
textProperty = ko.unwrap(setup.optionsText), | |
valueProperty = ko.unwrap(setup.optionsValue), | |
dataItems = ko.unwrap(setup.options), | |
myValue = setup.value, | |
koValue = allBindingsAccessor().value, | |
datalist = document.createElement("DATALIST"); | |
// create an associated <datalist> element | |
datalist.id = element.getAttribute("list"); | |
document.body.appendChild(datalist); | |
// when the value is changed, write to the associated myValue observable | |
function onNewValue(newVal) { | |
var dataItems = ko.unwrap(setup.options), | |
selectedItem = findItem(dataItems, textProperty, newVal), | |
newValue = selectedItem ? getVal(selectedItem, valueProperty) : void 0; | |
if (ko.isWriteableObservable(myValue)) { | |
myValue(newValue); | |
} | |
} | |
// listen for value changes | |
// - either via KO's value binding (preferred) or the change event | |
if (ko.isSubscribable(koValue)) { | |
koValue.subscribe(onNewValue); | |
} else { | |
ko.utils.registerEventHandler(element, "change", function () { | |
onNewValue(this.value); | |
}); | |
} | |
// init the element's value | |
// - either via the myValue observable (preferred) or KO's value binding | |
if (ko.isObservable(myValue) && myValue()) { | |
element.value = getVal(findItem(dataItems, valueProperty, myValue()), textProperty); | |
} else if (ko.isObservable(koValue) && koValue()) { | |
onNewValue(koValue()); | |
} | |
}, | |
update: function (element, valueAccessor) { | |
var setup = valueAccessor(), | |
datalist = element.list, | |
dataItems = ko.unwrap(setup.options), | |
textProperty = ko.unwrap(setup.optionsText); | |
// rebuild list of options when an underlying observable changes | |
datalist.innerHTML = ""; | |
ko.utils.arrayForEach(dataItems, function (item) { | |
var option = document.createElement("OPTION"); | |
option.value = getVal(item, textProperty); | |
datalist.appendChild(option); | |
}); | |
ko.utils.triggerEvent(element, "change"); | |
} | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment