knockout.js - 是否有一个公认的约定来处理用户输入之前为 "yes-no"的 "unset"下拉菜单?

标签 knockout.js javascript knockout-2.0

我认为这一定是一种常见的情况,我想知道在 Knockout 中是否有一个公认的惯例来处理这个问题。你有一个“是-否”下拉菜单(或一对单选按钮),它的默认值是一个空白项目(或两个都未选中,对于单选按钮)。用户必须做出选择才能继续。

这并不能完美地映射到您模型中的 bool 值,因为实际上存在三个可能的值。 True、False 和没有用户选择。在 C# 中,您可能会考虑使用 nullable bool 值,在 Java 中你可以使用 java.lang.Boolean .在这两种情况下,“null”都可以表示没有用户选择。

JavaScript 没有可空值,但由于它不强制变量类型,您可以采用特定变量可以为 null、true 或 false 的约定,并以类似于 C# 中可空 bool 值的方式使用它或 java.lang.Boolean。

首先,存在绑定(bind)到 bool 值的问题。 Knockout 希望所有的绑定(bind)值默认都是字符串类型。这是讨论herehere ,而 RP Niemeyer 提供的解决方案是使用自定义绑定(bind),如下所示:( Link to JS Fiddle for this example )

ko.bindingHandlers.booleanValue = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var observable = valueAccessor(),
            interceptor = ko.computed({
                read: function() {
                    return observable().toString();
                },
                write: function(newValue) {
                    observable(newValue === "true");
                }                   
            });

        ko.applyBindingsToNode(element, { value: interceptor });
    }
};

所以我以此为出发点,想出了这个自定义绑定(bind)。它似乎工作。我对社区对此方法的反馈很感兴趣。查看jsfiddle for this自己试验一下。这有什么缺点和/或可扩展性问题吗?

ko.bindingHandlers.nullableBooleanValue = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var observable = valueAccessor(),
            interceptor = ko.computed({
                read: function() {                                           
                    console.log(observable());
                    console.log(typeof(observable()));

                    var result = null;
                    if(observable() === true){
                        result = "true";
                    } else if(observable() === false){
                        result = "false";
                    } else { // Default is null, which represents no user selection
                        result = "null";
                    }

                    console.log("transforming on read:")
                    console.log(typeof(observable()));
                    console.log(observable());
                    console.log(typeof(result));
                    console.log(result);
                    return result;
                },
                write: function(newValue) {
                    var result = null;
                    if(newValue === "true"){
                        result = true;
                    } else if(newValue === "false"){
                        result = false;
                    } else { // Default is null, which represents no user selection
                        result = null;
                    }

                    console.log("transforming on write:")
                    console.log(typeof(newValue));
                    console.log(newValue);
                    console.log(typeof(result));
                    console.log(result);
                    observable(result);
                }                   
            });

        ko.applyBindingsToNode(element, { value: interceptor });
    }
};

var model = {
    state: ko.observable(null)
};

ko.applyBindings(model);

最佳答案

好吧,扩展器方法并没有按照我想要的方式工作,所以我放弃了它(仍在编辑历史中,如果你好奇的话)。我修改了您的绑定(bind)以将选项放在上面,这样您就不会在 HTML 中指定它们。您还可以选择指定“Null”选项文本(您可以扩展它以允许设置每个标签)。

此方法可让您将可观察对象视为标准的可空 bool 值。这是 HTML(注意,nullLabel 是完全可选的):

<select data-bind="yesNoNull: answer, nullLabel: 'Null' "></select>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>​

这是绑定(bind):

ko.bindingHandlers.yesNoNull = {    
    init: function(element, valueAccessor, allBindingsAccessor) {
        var target = valueAccessor();
        var nullLabel = allBindingsAccessor().nullLabel || "";
        var options = function() { return [ nullLabel, "Yes", "No"]; };
        ko.bindingHandlers.options.update(element, options, allBindingsAccessor);

        var observable = valueAccessor(),
            interceptor = ko.computed({
                read: function() {
                    var result = nullLabel;
                    if(observable() === true){
                        result = "Yes";
                    } else if(observable() === false){
                        result = "No";
                    }
                    return result;
                },
                write: function(newValue) {
                    var result = null;
                    if(newValue === "Yes"){
                        result = true;
                    } else if(newValue === "No"){
                        result = false;
                    }
                    observable(result);
                }                   
            });

        ko.applyBindingsToNode(element, { value: interceptor });
    }
};

这里是 the fiddle .

关于knockout.js - 是否有一个公认的约定来处理用户输入之前为 "yes-no"的 "unset"下拉菜单?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13293341/

相关文章:

javascript - 菜单动画从顶部功能滑动

javascript - Fancybox 宽度不适用 - autoSize : false not the answer

javascript - Knockout.js:计算的可观察对象未按预期更新

javascript - knockoutjs 单击绑定(bind)在嵌套的 foreach 中不起作用

javascript - 与 Javascript 中的 If else 语句比较问题

knockout.js 根据数组是否为空来更改可见状态

javascript - Knockout.js - foreach 表的每一行上的文本输入,应该只编辑该行上的字段

javascript - 使用 knockout 的 "placeholder” 属性 - JSON

javascript - 在knockoutjs中始终使用jquerylideUpslideDown

knockout.js - knockout : Adding to observable Arrays in Nested ViewModels