如何使用 KnockoutJS 和 JQuery UI 创建自动完成组合框
Posted
技术标签:
【中文标题】如何使用 KnockoutJS 和 JQuery UI 创建自动完成组合框【英文标题】:How to create an autocomplete combobox with KnockoutJS and JQuery UI 【发布时间】:2020-04-03 18:11:51 【问题描述】:我一直在尝试根据this post 中接受的响应创建一个自动完成下拉菜单,但自动完成下拉菜单根本没有出现。可能是因为响应是 9 岁,或者我做错了什么。我已经尝试了我遇到的所有建议。是否有使用 jquery 1.12.3 版、jquery-ui 1.12.1 版和 knockoutjs 3.4.1 版创建此组合框的更新方法?
对我来说,绑定似乎并没有真正发生,因为我可以将自定义绑定重命名为“jqAuto1”而不是“jqAuto”,并且不会出现错误,即使“jqAuto1”没有在任何地方定义。为什么不被捡起来?
这是我的代码。请注意,JS 脚本与 CShtml 和 TS 文件位于单独的父解决方案中。浏览器仍然会找到并执行 JS 脚本。
CSHTML
<input class="form-control form-control-xs" data-bind="value: companyName, jqAuto: autoFocus: true , jqAutoSource: myComp, jqAutoValue: mySelectedGuid, jqAutoSourceLabel: 'displayName', jqAutoSourceInputValue: 'coname', jqAutoSourceValue: 'id'" placeholder="Type Company Name and select from list" />
TS
// For list of Companies
class Comp
_id: KnockoutObservable<string>;
_coname: KnockoutObservable<string>;
_coid: KnockoutObservable<string>;
constructor(id: string, coname: string, coid: string)
this._id = ko.observable(id);
this._coname = ko.observable(coname);
this._coid = ko.observable(coid);
myComp: KnockoutObservableArray<Comp>;
mySelectedGuid: KnockoutObservable<string>;
displayName: KnockoutComputed<string>;
...
this.myComp = ko.observableArray([
new Comp("1", "Company 1", "CO1"),
new Comp("2", "Company 2", "CO2"),
new Comp("3", "Company 3", "CO3"),
new Comp("4", "Company 4", "CO4"),
new Comp("5", "Company 5", "CO5")
]);
this.companyName = ko.validatedObservable<string>("");
this.displayName = ko.computed(function ()
return this.myComp.coname + " [" + this.myComp.coid + "]";
, this);
this.mySelectedGuid = ko.observable("5");
JS 几乎是链接帖子中的内容
(function ()
var global = this || (0, eval)('this'),
document = global['document'],
moduleName = 'knockout-binding-jqauto',
dependencies = ['knockout', 'jquery'];
var moduleDance = function (factory)
// Module systems magic dance.
if (typeof define === "function" && define["amd"])
define(moduleName, dependencies.concat('exports'), factory);
else
// using explicit <script> tags with no loader
global.CPU = global.CPU || ;
factory(global.ko, global.Globalize);
;
var factory = function (ko, $)
ko.bindingHandlers.jqauto =
init: function (element, valueAccessor, allBindings, viewModel, bindingContext)
var options = valueAccessor() || ,
allBindings = allBindingsAccessor(),
unwrap = ko.utils.unwrapObservable,
modelValue = allBindings.jqAutoValue,
source = allBindings.jqAutoSource,
valueProp = allBindings.jqAutoSourceValue,
inputValueProp = allBindings.jqAutoSourceInputValue || valueProp,
labelProp = allBindings.jqAutoSourceLabel || valueProp;
//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();
alert(currentValue);
var matchingItem = ko.utils.arrayFirst(unwrap(source), function (item)
return unwrap(inputValueProp ? item[inputValueProp] : item) === currentValue;
);
if (!matchingItem)
writeValueToModel(null);
//handle the choices being updated in a DO, to decouple value updates from source (options) updates
var mappedSource = ko.dependentObservable(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;
, null, disposeWhenNodeIsRemoved: element );
//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();
//initialize autocomplete
$(element).autocomplete(options);
,
update: function (element, valueAccessor, allBindings, 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;
) || ; //probably don't need the || , but just protect against a bad value
//update the element with the value that should be shown in the input
$(element).val(modelValue && inputValueProp !== valueProp ? unwrap(modelValue[inputValueProp]) : modelValue.toString());
;
moduleDance(factory);
)();
【问题讨论】:
这个怎么样? jqueryui.com/autocomplete @panoskarajohn 淘汰赛需要通过自定义绑定连接到自动完成。我试过了:ko.bindingHandlers.jqAutoComplete = update: function (element, valueAccessor, allBindingsAccessor, viewModel) var companies = valueAccessor(); $(element).autocomplete( source: valueAccessor() ); ;
@panoskarajohn 然后我尝试像这样使用它:<input data-bind="value: companyName, jqAutoComplete: companies"/>
。还是不行
我会发布一个答案。我没有完全理解你的问题。但是为什么你甚至需要淘汰赛?
@panoskarajohn 在我之前参与这个项目的团队集成了淘汰赛并以我需要使用自定义绑定或解构在我之前完成的所有内容的方式构建项目
【参考方案1】:
我还没有完全理解你的问题。但淘汰赛与 UIComplete 无关。请看一个使用 UI Complete 的简单示例。
async function autocomplete()
const sthings= await getSthings(); //gets json array, or ajax call, this is a promise
$("#sthHighlightSearch").autocomplete(
source: sthings
);
//This is an extension method for autocomplete
//Should filter the list with starts with characters written in the autocomplete
$.ui.autocomplete.filter = function (array, term)
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
return $.grep(array, function (value)
return matcher.test(value.label || value.value || value);
);
;
【讨论】:
以上是关于如何使用 KnockoutJS 和 JQuery UI 创建自动完成组合框的主要内容,如果未能解决你的问题,请参考以下文章
使用 jquery-ui datepicker 的 knockoutjs 数据绑定
通过 Jquery Ajax 函数加载后不渲染 KnockoutJS 元素
我应该花精力实现 knockoutjs 还是研究 jQuery Data Link [关闭]
将 jquery ui 对话框与 knockoutjs 集成