KnockoutJS没有在自定义绑定处理程序中调用更新函数

时间:2012-10-25 09:51:33

标签: jquery-plugins knockout.js

我编写了一个多选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 select元素转换为我的自定义多选。

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

在页面完全加载并且我更改了我绑定的observable的值之后,根本不会触发更新函数!

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

任何想法可能是什么问题?

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

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

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

JSFiddle(破碎):http://jsfiddle.net/padfv0u9/

JSFiddle(已修复):http://jsfiddle.net/padfv0u9/2/