jQuery UI autocomplete

https://groups.google.com/d/topic/knockoutjs/ABhEeI7jLKA/discussion

by PhilM

HTML

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/base/jquery-ui.css">
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-latest.debug.js"></script>
<input data-bind="jqAuto: { autoFocus: true }, jqAutoSource: myOptions, jqAutoValue: mySelectedOption, jqAutoSourceLabel: 'name', jqAutoSourceValue: 'id'" />

<hr/>

<div data-bind="text: ko.toJSON(mySelectedOption)"></div>

JavaScript

// forked from https://groups.google.com/forum/#!topic/knockoutjs/ABhEeI7jLKA/discussion

//jqAuto -- additional options to pass to autocomplete
//jqAutoSource -- the array of choices
//jqAutoValue -- where to write the selected value
//jqAutoSourceLabel -- the property name that should be displayed in the possible choices
//jqAutoSourceValue -- the property name to use for the value
ko.bindingHandlers.jqAuto = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var options = valueAccessor() || {};
        var allBindings = allBindingsAccessor();
        var unwrap = ko.utils.unwrapObservable;
        
        //handle value changing
        var modelValue = allBindings.jqAutoValue;
        if (modelValue) {
            var handleValueChange = function(event, ui) {
                var valueToWrite = ui.item ? ui.item.value : $(element).val();
                if (ko.isWriteableObservable(modelValue)) {
                   modelValue(valueToWrite );  
                    
                } else {  //write to non-observable
                   if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['jqAutoValue'])
                            allBindings['_ko_property_writers']['jqAutoValue'](valueToWrite );    
                }
            };
            
            options.change = handleValueChange;
            options.select = handleValueChange;  
        }
        
        //handle the choices being updated in a DO, so the update function doesn't have to do it each time the value is updated
        var mappedSource = ko.dependentObservable(function() {
            var source = unwrap(allBindings.jqAutoSource);
            var valueProp = unwrap(allBindings.jqAutoSourceValue);
            var labelProp = unwrap(allBindings.jqAutoSourceLabel) || valueProp;
            
            var mapped = ko.utils.arrayMap(source, function(item) {
                var result = {};
                result.label =...