Knockout.js 是否有公认的处理惯例;“是或否”;下拉列表中的;“未设置”;在用户输入之前?

Knockout.js 是否有公认的处理惯例;“是或否”;下拉列表中的;“未设置”;在用户输入之前?,knockout.js,javascript,knockout-2.0,Knockout.js,Javascript,Knockout 2.0,我认为这是一种常见的情况,我想知道是否有一个公认的惯例,如何在淘汰赛中处理这个问题。您有一个“是-否”下拉列表(或一对单选按钮),它的默认值是一个空白项(对于单选按钮,或两者都未选中)。用户必须做出选择才能继续 这并不完全映射到模型中的布尔值,因为实际上有三个可能的值。True、false和无用户选择。在C语言中,你可以考虑使用布尔值,而在java中你可以使用。在这两种情况下,“null”都不能表示用户选择 JavaScript没有可空值,但由于它不强制变量类型,因此可以采用一种约定,即特定变量

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

这并不完全映射到模型中的布尔值,因为实际上有三个可能的值。True、false和无用户选择。在C语言中,你可以考虑使用布尔值,而在java中你可以使用。在这两种情况下,“null”都不能表示用户选择

JavaScript没有可空值,但由于它不强制变量类型,因此可以采用一种约定,即特定变量可以为null、true或false,并以与C#中的可空布尔值或java.lang.boolean类似的方式使用它

首先,是绑定到布尔值的问题。Knockout希望所有绑定值在默认情况下都是字符串类型。本文对此进行了讨论,RP Niemeyer提供的解决方案是使用自定义绑定,如下所示:()

所以我用它作为我的出发点,我提出了这个定制绑定。它似乎起作用了。我对社区对这种方法的反馈很感兴趣。签出该文件以自己进行实验。这有什么缺点和/或可伸缩性问题吗

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);

好的,extender方法并没有按照我希望的方式工作,所以我放弃了它(如果您好奇的话,它仍在编辑历史记录中)。我修改了你的绑定,让它把选项放在上面,这样你就不用在HTML中指定它们了。您还可以选择指定“Null”选项文本(可以展开此选项以允许设置每个标签)

此方法允许您将可观察对象视为标准的可空布尔值。以下是HTML(注意,
nullLabel
是完全可选的):


这是。

你能解释一下这条线是干什么用的吗<代码>拦截器.options=[选项| |“”,“是”,“否”]如果我正确阅读了您的示例,interceptor.options将设置为空字符串“”。但我看不出它在哪里或如何被使用。谢谢谢谢你的澄清。然而,有些事情并不正常。我不确定我是否做错了什么,但当我尝试为ViewModel字段“answer”赋值时,更改不会传播回select元素@该死的,我没试过。它不起作用,因为布尔值在下拉列表的选项中没有显示对应项。我正在做一个更新,可能要到明天。谢谢你的反馈和探索一些不同的选择,泰尔修斯!
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);
<select data-bind="yesNoNull: answer, nullLabel: 'Null' "></select>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>​
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 });
    }
};