繁体   English   中英

如何使用 KnockoutJS 和 JQuery UI 创建自动完成组合框

[英]How to create an autocomplete combobox with KnockoutJS and JQuery UI

我一直在尝试根据这篇文章中接受的响应创建一个自动完成下拉列表,但自动完成下拉列表根本没有显示。 这可能是因为响应已经 9 年了,或者我做错了什么。 我已经尝试了我遇到的所有建议。 是否有使用 jquery 版本 1.12.3、jquery-ui 版本 1.12.1 和knockoutjs 版本 3.4.1 创建此组合框的更新方法?

对我来说似乎绑定并没有真正发生,因为我可以将自定义绑定重命名为“jqAuto1”而不是“jqAuto”并且不会有错误,即使“jqAuto1”没有在任何地方定义。 怎么没被收?

这是我的代码。 请注意,JS 脚本位于独立于 CSHTML 和 TS 文件的父解决方案中。 浏览器仍然会找到并执行 JS 脚本。

网页版

<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);
})();

我还没有完全理解你的问题。 但是淘汰赛与 UIComplete 无关。 请参阅使用 UI 完成的简单示例。

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);
        });
    };

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM