有谁知道用Knockout JS模板创建自动完成组合框的最佳方法吗?
我有以下模板:
<script type="text/html" id="row-template"> <tr> ... <td> <select class="list" data-bind="options: SomeViewModelArray, value: SelectedItem"> </select> </td> ... <tr> </script>
有时候,这个清单很长,我想让Knockout在jQuery自动完成功能或一些直接的JavaScript代码方面表现出色,但收效甚微。
另外,jQuery.Autocomplete需要输入字段。有任何想法吗?
这是我编写的jQuery UI自动完成绑定。它的目的是镜像options,optionsText,optionsValue,value与几个新增的选择要素使用绑定模式(可以查询通过AJAX选项,你可以区分什么是显示在输入框中输入与所显示的选择框弹出起来。
options
optionsText
optionsValue
value
您无需提供所有选项。它将为您选择默认值。
//jqAuto -- main binding (should contain additional options to pass to autocomplete) //jqAutoSource -- the array to populate with choices (needs to be an observableArray) //jqAutoQuery -- function to return choices (if you need to return via AJAX) //jqAutoValue -- where to write the selected value //jqAutoSourceLabel -- the property that should be displayed in the possible choices //jqAutoSourceInputValue -- the property that should be displayed in the input box //jqAutoSourceValue -- the property to use for the value ko.bindingHandlers.jqAuto = { init: function(element, valueAccessor, allBindingsAccessor, viewModel) { var options = valueAccessor() || {}, allBindings = allBindingsAccessor(), unwrap = ko.utils.unwrapObservable, modelValue = allBindings.jqAutoValue, source = allBindings.jqAutoSource, query = allBindings.jqAutoQuery, valueProp = allBindings.jqAutoSourceValue, inputValueProp = allBindings.jqAutoSourceInputValue || valueProp, labelProp = allBindings.jqAutoSourceLabel || inputValueProp; //function that is shared by both select and change event handlers function writeValueToModel(valueToWrite) { 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 ); } } //on a selection write the proper value to the model options.select = function(event, ui) { writeValueToModel(ui.item ? ui.item.actualValue : null); }; //on a change, make sure that it is a valid value or clear out the model value options.change = function(event, ui) { var currentValue = $(element).val(); var matchingItem = ko.utils.arrayFirst(unwrap(source), function(item) { return unwrap(item[inputValueProp]) === currentValue; }); if (!matchingItem) { writeValueToModel(null); } } //hold the autocomplete current response var currentResponse = null; //handle the choices being updated in a DO, to decouple value updates from source (options) updates var mappedSource = ko.dependentObservable({ read: function() { mapped = ko.utils.arrayMap(unwrap(source), function(item) { var result = {}; result.label = labelProp ? unwrap(item[labelProp]) : unwrap(item).toString(); //show in pop-up choices result.value = inputValueProp ? unwrap(item[inputValueProp]) : unwrap(item).toString(); //show in input box result.actualValue = valueProp ? unwrap(item[valueProp]) : item; //store in model return result; }); return mapped; }, write: function(newValue) { source(newValue); //update the source observableArray, so our mapped value (above) is correct if (currentResponse) { currentResponse(mappedSource()); } } }); if (query) { options.source = function(request, response) { currentResponse = response; query.call(this, request.term, mappedSource); } } else { //whenever the items that make up the source are updated, make sure that autocomplete knows it mappedSource.subscribe(function(newValue) { $(element).autocomplete("option", "source", newValue); }); options.source = mappedSource(); } ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(element).autocomplete("destroy"); }); //initialize autocomplete $(element).autocomplete(options); }, update: function(element, valueAccessor, allBindingsAccessor, viewModel) { //update value based on a model change var allBindings = allBindingsAccessor(), unwrap = ko.utils.unwrapObservable, modelValue = unwrap(allBindings.jqAutoValue) || '', valueProp = allBindings.jqAutoSourceValue, inputValueProp = allBindings.jqAutoSourceInputValue || valueProp; //if we are writing a different property to the input than we are writing to the model, then locate the object if (valueProp && inputValueProp !== valueProp) { var source = unwrap(allBindings.jqAutoSource) || []; var modelValue = ko.utils.arrayFirst(source, function(item) { return unwrap(item[valueProp]) === modelValue; }) || {}; } //update the element with the value that should be shown in the input $(element).val(modelValue && inputValueProp !== valueProp ? unwrap(modelValue[inputValueProp]) : modelValue.toString()); } };
您将使用它像:
<input data-bind="jqAuto: { autoFocus: true }, jqAutoSource: myPeople, jqAutoValue: mySelectedGuid, jqAutoSourceLabel: 'displayName', jqAutoSourceInputValue: 'name', jqAutoSourceValue: 'guid'" />