Knockoutjs - 自动完成“窃取”更改事件

Knockoutjs - Autocomplete "steals" change event

本文关键字:窃取 事件 Knockoutjs      更新时间:2023-09-26

我正在使用自动完成功能,但同时我希望更改事件在模糊或更改时将值保存在 db 中。

<input type="text" data-bind="event: {change: $parent.saveVariable},
    autocomplete:{
        url: $root.api.autocomplete.searchMasterVariableUrl(),
        renderitem: renderMasterVariableSearch,
        onselection: function (item) { if (item.text) masterText(item.text); }
    }, 
    autocompletevalue: masterCode" />

这行不通...如果我删除自动完成功能,它可以工作!!!

有什么建议吗?

此致敬意阿诺

自动完成的实现如下所示(它是一个绑定处理程序):

(函数 ($, ko) {

ko.bindingHandlers.autocomplete = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var $element = $(element),
            opt = valueAccessor(),
            allBindings = allBindingsAccessor();
        function writeToModel(newValue) {
            if (!ko.isObservable(allBindings.autocompletevalue) || ko.isWriteableObservable(allBindings.autocompletevalue)) {
                var currentValue = ko.utils.unwrapObservable(allBindings.autocompletevalue);
                if (newValue && $.isFunction(opt.valueselector)) {
                    newValue = opt.valueselector.call(this, newValue);
                }
                else if (newValue && newValue.label) {
                    newValue = newValue.label;
                }
                if (currentValue !== newValue) {
                    if (ko.isWriteableObservable(allBindings.autocompletevalue)) {
                        allBindings.autocompletevalue(newValue);
                    }
                    else {
                        allBindings.autocompletevalue = newValue;
                    }
                }
            }
        }
        var config = {
            minLength: opt.minLength || 2,
            source: function (request, response) {
                var req = { term: request.term };
                if($.isFunction(opt.requestdataselector)) {
                    opt.requestdataselector.call(this, req);
                }
                $.getJSON(opt.url, req, function (data, status, xhr) {
                    if (opt.label) {
                        if (typeof opt.label === 'string') {
                            $.each(data, function (idx, el) { el.label = el[opt.label]; });
                        }
                        else if ($.isFunction(opt.label)) {
                            $.each(data, function (idx, el) { el.label = opt.label.call(this, el); });
                        }
                    }
                    response(data);
                }).fail(function(error) {
                    toastr.error('Failed autocomplete search: ' + error.responseText);
                });
            },
            focus: function (ev, ui) {
                $element.val(ui.item.label);
                return false;
            },
            select: function (ev, ui) {
                $element.val(ui.item.label);
                writeToModel(ui.item);
                if ($.isFunction(opt.onselection)) {
                    var ctx = ko.dataFor(this);
                    opt.onselection.call(ctx, ui.item);
                    if ($.isFunction(opt.afterselection)) {
                        opt.afterselection.call(this, $element, ui.item, this);
                    }
                }
                return false;
            },
            change: function (ev, ui) {
                var val = $(ev.target).val();
                if (opt.allowcustomtext) {
                    writeToModel(val);
                }
                else {
                    if (ko.isObservable(allBindings.autocompletevalue) && allBindings.autocompletevalue() !== val) {
                        $element.val(null);
                        writeToModel(null);
                    }
                }
            }
        };
        var subscription;
        if (ko.isWriteableObservable(allBindings.autocompletevalue)) {
            subscription = allBindings.autocompletevalue.subscribe(function (newValue) {
                $element.val(newValue);
            });
            var val = ko.utils.unwrapObservable(allBindings.autocompletevalue);
            $element.val(val);
        }
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $element.autocomplete("destroy");
            if (subscription) {
                subscription.dispose();
            }
        });
        $element.autocomplete(config);
        if($.isFunction(opt.onenter)) {
            $element.on('keydown', function (ev) {
                if(ev.keyCode === 13) {
                    ev.preventDefault();
                    ev.stopPropagation();
                    opt.onenter.call(this, ko.dataFor(ev.target), ev.target);
                }
            });
        }
        if ($.isFunction(opt.renderitem)) {
            $element.data("ui-autocomplete")._renderItem = opt.renderitem;
        }
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var $element = $(element),
            opt = valueAccessor(),
            allBindings = allBindingsAccessor();
        if (ko.isObservable(allBindings.autocompletevalue)) {
            var val = allBindings.autocompletevalue();
            $element.val(val);
        }
    }
};

})(jQuery, ko);

我更新了上面人提交的代码,改用自动完成的更改。

简而言之,自动完成具有自己的更改参数和回调。

$( ".selector" ).autocomplete({
    change: function( event, ui ) {}
});

JsFiddle 示例

<label for="name-search">Search language:</label>
<input type="text" id="name-search" data-bind="value: langName, 
ko_autocomplete: { change: handleChange, source: getLangs(), select: addLang }" />
<div style="margin-top:1em">The observable array contains the following elements:
    <ul data-bind="foreach: selectedLangs">
        <li data-bind="text: $data" />
    </ul>
</div>
<div id="pickedval">test</div>
<input type="text" value="for using tab">
ko.bindingHandlers.ko_autocomplete = {
    init: function (element, params) {
        $(element).autocomplete(params());
    },
    update: function (element, params) {
        $(element).autocomplete("option", "source", params().source);
    }
        };
$(document).ready(
function () {
    var availableTags = [{
        label: "ActionScript",
        value: 1
    }, {
        label: "AppleScript",
        value: 2
    }, {
        label: "Asp",
        value: 3
    }, {
        label: "BASIC",
        value: 4
    }, {
        label: "C",
        value: 5
    }, {
        label: "C++",
        value: 6
    }, {
        label: "Clojure",
        value: 7
    }, {
        label: "COBOL",
        value: 8
    }, {
        label: "ColdFusion",
        value: 9
    }, {
        label: "Erlang",
        value: 10
    }, {
        label: "Fortran",
        value: 11
    }, {
        label: "Groovy",
        value: 12
    }, {
        label: "Haskell",
        value: 13
    }, {
        label: "Java",
        value: 14
    }, {
        label: "JavaScript",
        value: 15
    }, {
        label: "Lisp",
        value: 16
    }, {
        label: "Perl",
        value: 17
    }, {
        label: "PHP",
        value: 18
    }, {
        label: "Python",
        value: 19
    }, {
        label: "Ruby",
        value: 20
    }, {
        label: "Scala",
        value: 21
    }, {
        label: "Scheme",
        value: 22
    }];
    // knockout view model                    
    var ViewModel = function () {
        var self = this;
        self.langName = ko.observable();
        self.selectedLangs = ko.observableArray();
        self.handleChange = function () {
            alert("change event fired");
            return true;
        }
        // return some programming languages
        self.getLangs = function () {
            return availableTags;
        }
        // user clicked on a auto complete item
        self.addLang = function (event, ui) {
            $(event.target).val("");
            self.handleChange(event);
            var lang = ui.item.label;
            var id = ui.item.value;
            self.selectedLangs.push("id: " + id + ", Language: " + lang);
            return false;
        }
        return {
            getLangs: self.getLangs,
            addLang: self.addLang,
            langName: self.langName,
            handleChange: self.handleChange,
            selectedLangs: self.selectedLangs
        }
    };
    //bind knockout model
    ko.applyBindings(new ViewModel());
});