【问题标题】:How to bind a checkbox to the inverse of a value?如何将复选框绑定到值的倒数?
【发布时间】:2012-02-12 17:28:29
【问题描述】:

当我需要将复选框和另一个 DOM 元素的可见性绑定到我的 viewModel 的布尔属性的逆时,我遇到了这种情况:

<input type="checkbox" data-bind="checked: needsReview"> Not Required 
<br>
<div id="Some related text" data-bind="visible: needsReview"> other stuff here </div>
var dataFromSever = { needsReview: true };

var theModel = function (jsonData) {
    var self = this;
    ko.mapping.fromJS(jsonData, {}, self);
}

ko.applyBindings(new theModel(dataFromSever));

我的实际数据模型中有不止一个这样的属性,所以我不想创建多个ko.computed() 字段。我只想绑定到"checked: !needsReview()" 或同样易于维护的东西。

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    有几种类似的方法可以处理这个问题。基本思想是你需要创建一个可写的计算 observable 来绑定复选框。

    您可以直接在模型中执行此操作,使用扩展器,或通过向可观察基础 (ko.observable.fn) 添加函数。

    但是,由于您使用的是映射插件,并且可能不想自定义创建对象的方式或添加其他属性,因此我认为使用自定义绑定是最佳选择。你的模型真的不需要关心维护你的属性的逆,所以我们实际上可以在绑定时做这部分。

    这是一个inverseChecked 绑定,它在您的真实可观察对象和绑定之间插入一个可写的计算可观察对象。然后,它只是使用真正的检查绑定来完成它的工作。

    ko.bindingHandlers.inverseChecked = {
        init: function(element, valueAccessor, allBindingsAccessor) {
            var value = valueAccessor();
            var interceptor = ko.computed({
                                read: function() {
                                    return !value();
                                },
                                write: function(newValue) {
                                    value(!newValue);
                                },
                                disposeWhenNodeIsRemoved: element
                            }); 
    
            var newValueAccessor = function() { return interceptor; };
    
    
            //keep a reference, so we can use in update function
            ko.utils.domData.set(element, "newValueAccessor", newValueAccessor);
            //call the real checked binding's init with the interceptor instead of our real observable
            ko.bindingHandlers.checked.init(element, newValueAccessor, allBindingsAccessor);
        },
        update: function(element, valueAccessor) {
            //call the real checked binding's update with our interceptor instead of our real observable
            ko.bindingHandlers.checked.update(element, ko.utils.domData.get(element, "newValueAccessor"));  
        }
    };
    

    这是一个示例:http://jsfiddle.net/rniemeyer/Kz4Tf/

    对于您的visible 绑定,您可以执行visible: !needsReview()

    【讨论】:

    • 谢谢。这看起来正是我需要的。看起来它应该比这更简单,不是吗?我看看我今天早上能不能把它连接起来......
    • 很酷的答案,马上。但我想知道,为什么不直接使用单选按钮?
    • 我认为他不想同时绑定两者。只是想将一个复选框绑定到他的模型所持有的反面。我只是在示例中添加了两者,以表明它会响应模型的更改或 UI 中的反向更改。
    • 我对它进行了一点更新,因为我们真的应该在 init/update 中使用相同的计算 observable,而不是返回一个新的 observable。不改变功能。
    • 这似乎不适用于 KO v3。只是尝试了一下,没有运气。不过,这是一个简单的修复,只需使用 ko.bindingHandlers.checked.init 而不是 update
    【解决方案2】:

    我一般在 KO 中做一个自定义的 bindingHandler 就是 visible 的逆:

    ko.bindingHandlers['invisible'] = {
    
        update: function(element, valueAccessor){
            var val = ko.utils.unwrapObservable(valueAccessor());
    
            ko.bindingHandlers['visible'].update(element, function() { return !val; });            
        }
    }
    

    这使您可以像您所描述的那样干净利落地满足您的需求,而不会将您的 data-bind 语句与丑陋的 !val() 混淆

    【讨论】:

    • 谢谢,但这只会处理 visible 绑定。它不会解决 checkbox 绑定问题。
    • 是的 - Ryan 在另一半问题上击败了我。将这两个绑定处理程序添加到您的项目中应该可以让您清理很多绑定语句。
    【解决方案3】:

    我更喜欢反转可观察/计算值的更通用和通用的方法(不依赖于任何特定绑定):

    /**
     * A small handy observable / computed function that wraps around the inverse of it's boolean value.
     * @author Nir Azuelos
     * @returns {Function}
     */
    ko.observable.fn.inverse = ko.computed.fn.inverse = function() {
        return ko.pureComputed(function() { return !this(); }, this);
    };
    

    用法:

    <div data-bind="visible: myObservable.inverse()">
    

    【讨论】:

    • myObservable 未更新。这是一种单向绑定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    相关资源
    最近更新 更多