2

我编写了一个多选 jQuery 插件,可以应用于普通的 HTML 选择元素。

但是,此插件将解析 select 元素及其选项,然后从 DOM 中删除 select 元素并插入 div 和复选框的组合。

我在 Knockout 中创建了一个自定义绑定处理程序,如下所示:

ko.bindingHandlers.dropdownlist = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here

    // Retrieve the value accessor
    var value = valueAccessor();
    // Get the true value of the property
    var unwrappedValue = ko.utils.unwrapObservable(value);

    // Check if we have specified the value type of the DropDownList items. Defaults to "int"
    var ddlValueType = allBindingsAccessor().dropDownListValueType ? allBindingsAccessor().dropDownListValueType : 'int';

    // Check if we have specified the INIMultiSelect options otherwise we will use our defaults.
    var elementOptions = allBindingsAccessor().iniMultiSelectOptions ? allBindingsAccessor().iniMultiSelectOptions :
        {
            multiple: false,
            onItemSelectedChanged: function (control, item) {
                var val = item.value;

                if (ddlValueType === "int") {
                    value(parseInt(val));
                }
                else if (ddlValueType == "float") {
                    value(parseFloat(val));
                } else {
                    value(val);
                }
            }
        };

    // Retrieve the attr: {} binding
    var attribs = allBindingsAccessor().attr;

    // Check if we specified the attr binding
    if (attribs != null && attribs != undefined) {

        // Check if we specified the attr ID binding
        if (attribs.hasOwnProperty('id')) {
            var id = attribs.id;

            $(element).attr('id', id);
        }

        if (bindingContext.hasOwnProperty('$index')) {
            var idx = bindingContext.$index();

            $(element).attr('name', 'ddl' + idx);
        }
    }

    if ($(element).attr('id') == undefined || $(element).attr('id') == '') {
        var id = "ko_ddl_id_" + (ko.bindingHandlers['dropdownlist'].currentIndex);

        $(element).attr('id', id);
    }

    if ($(element).attr('name') == undefined || $(element).attr('name') == '') {
        var name = "ko_ddl_name_" + (ko.bindingHandlers['dropdownlist'].currentIndex);

        $(element).attr('name', name);
    }

    var options = $('option', element);

    $.each(options, function (index) {
        if ($(this).val() == unwrappedValue) {

            $(this).attr('selected', 'selected');
        }
    });

    if (!$(element).hasClass('INIMultiSelect')) {
        $(element).addClass('INIMultiSelect');
    }

    $(element).iniMultiSelect(elementOptions);

    ko.bindingHandlers['dropdownlist'].currentIndex++;
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var unwrappedValue = ko.utils.unwrapObservable(valueAccessor());

    var id = $(element).attr('id').replace(/\[/gm, '\\[').replace(/\]/gm, '\\]');

    var iniMultiSelect = $('#' + id);

    if (iniMultiSelect != null) {
        iniMultiSelect.SetValue(unwrappedValue, true);
    }
}};
ko.bindingHandlers.dropdownlist.currentIndex = 0;

这会将原始的 HTML 选择元素转换为我的自定义多选。

但是,当第一次调用 update 函数时,在 init 之后,“element”变量仍将是原始的 select 元素,而不是我将自定义 html 保存在一起的包装器 div。

在页面完全加载并更改绑定到的可观察对象的值之后,根本不会触发更新功能!

不知何故,我有一种感觉,淘汰赛不再“知道”该做什么,因为我绑定到的原始 DOM 元素已经消失了......

有什么想法可能是这里的问题吗?

4

2 回答 2

0

Knockout 中有清理代码,当它确定元素不再是文档的一部分时,它将处理用于触发绑定的计算的 observables。

您可能会找到一种方法来隐藏原始元素,或者将绑定放置在原始元素的容器上select(可能是一个不错的选择),或者将绑定重新应用于其中一个新元素。

于 2012-10-25T13:50:32.180 回答
0

我今天遇到了类似的问题,这就是我解决它的方法。在我的更新处理程序中,我添加了以下行:

$(element).attr("dummy-attribute", ko.unwrap(valueAccessor()));

这足以防止处理程序被 Knockout 的垃圾收集器处理掉。

JSFiddle(坏了):http: //jsfiddle.net/padfv0u9/

JSFiddle(固定):http: //jsfiddle.net/padfv0u9/2/

于 2015-01-04T13:36:49.037 回答