针对不确定复选框的Knockout自定义绑定将不起作用

时间:2013-03-26 12:14:17

标签: javascript checkbox knockout.js custom-binding

让我们说一下:这是我的淘汰自定义绑定,用于将复选框置于不确定状态。

ko.bindingHandlers.nullableChecked = {
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value == null) element.indeterminate = true;
        ko.bindingHandlers.checked.update(element, function () { return value; });
    }
};

如果初始值为null,一切正常,复选框处于不确定状态,但是当我单击复选框时,它似乎不会将绑定属性的值更新为false / true。我错过了什么吗?

5 个答案:

答案 0 :(得分:4)

你不是在叫Init。

只需代理你的nullableChecked init函数中的init函数,就像在更新中一样。

ko.bindingHandlers.nullableChecked = {
    init: function(element, valueAccessor) {
          ko.bindingHandlers.checked.init(element, valueAccessor);
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value == null) element.indeterminate = true;
        ko.bindingHandlers.checked.update(element, valueAccessor);
    }
};

如果没有init,它实际上从未在复选框上设置“点击”绑定,以告知敲门声已发生变化。如果查看调试代码(http://knockoutjs.com/downloads/knockout-2.2.1.debug.js),您将看到init使用jQuery在复选框上设置“click”事件,以便在值更改时更新observable。

ko.bindingHandlers['checked'] = {
'init': function (element, valueAccessor, allBindingsAccessor) {
    var updateHandler = function() {
        var valueToWrite;
        if (element.type == "checkbox") {
            valueToWrite = element.checked;
        } else if ((element.type == "radio") && (element.checked)) {
            valueToWrite = element.value;
        } else {
            return; // "checked" binding only responds to checkboxes and selected radio buttons
        }

        var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
        if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
            // For checkboxes bound to an array, we add/remove the checkbox value to that array
            // This works for both observable and non-observable arrays
            var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
            if (element.checked && (existingEntryIndex < 0))
                modelValue.push(element.value);
            else if ((!element.checked) && (existingEntryIndex >= 0))
                modelValue.splice(existingEntryIndex, 1);
        } else {
            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
        }
    };
    ko.utils.registerEventHandler(element, "click", updateHandler);

    // IE 6 won't allow radio buttons to be selected unless they have a name
    if ((element.type == "radio") && !element.name)
        ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
},

编辑:这是一个小提琴:http://jsfiddle.net/cclose/NFfVn/

答案 1 :(得分:4)

@Fodagus的答案适用于Knockout&lt; = 2.3.0,但在Knockout&gt; = 3.0.0中,ko.bindingHandlers.checked.update未定义。

我们发现这在Knockout 3.1.0中适用于我们:

    ko.bindingHandlers.nullableChecked = {
        init: function (element, valueAccessor) {
            ko.bindingHandlers.checked.init(element, valueAccessor);
        },
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (value == null) {
                element.indeterminate = true;
            }
            else {
                element.indeterminate = false;
            }
        }
    };

我们遗失了什么吗?

答案 2 :(得分:3)

如果有人在这里希望选择所有类型复选框显示为中间,如果不是所有子项都被选中,则可以使用这样的简单绑定

ko.bindingHandlers.indeterminateValue = {
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        element.indeterminate = value;
    }
};

那么你可以像这样使用它

 <input type="checkbox" data-bind="checked: selectedAllProduce, indeterminateValue: selectedProduce().length > 0 && selectedProduce().length < produce.length" title="Select all/none"/>

这是一个小提琴,显示它正在处理计算的observable select all示例 https://jsfiddle.net/deannorth/crqwac12/

答案 3 :(得分:2)

knockout 3.0.0及更高版本的新版本中。删除checkbox绑定处理程序中的更新方法。因此,您应该在click event函数中创建init,以便在单击checkbox时触发更新方法。下面是将jquery checkbox转换为uniform checkbox的绑定处理程序示例。

ko.bindingHandlers.checkedUniform =
{
    init: function (element, valueAccessor) {
        ko.bindingHandlers.checked.init(element, valueAccessor);
        $(element).uniform().on('click', ko.bindingHandlers.checkedUniform.update);
    },
    update: function (element, valueAccessor) 
    {
        ko.bindingHandlers.checked.update(element, valueAccessor);
        $.uniform.update($(element));
    }
};

答案 4 :(得分:1)

checked处理程序接收存储的值的访问者,而不是持有该值的observable。因此,observable永远不会获得由处理程序引起的任何值更改。我认为你应该能够按原样传入值访问器。

ko.bindingHandlers.nullableChecked = {
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value == null) element.indeterminate = true;
        ko.bindingHandlers.checked.update(element, valueAccessor);
    }
};