3

これは一般的な状況である必要があると思います。ノックアウトでこれを処理する方法について受け入れられている慣習があるかどうか疑問に思います。「yes-no」ドロップダウン(またはラジオボタンのペア)があり、デフォルト値は空白の項目です(または、ラジオボタンの場合は両方ともオフになっています)。続行するには、ユーザーが選択する必要があります。

実際には3つの可能な値があるため、これはモデルのブール値に完全にはマッピングされません。真、偽、およびユーザー選択なし。C#ではnull許容ブール値の使用を検討し、Javaではjava.lang.Booleanを使用する場合があります。どちらの場合も、「null」はユーザーが選択されていないことを表す場合があります。

JavaScriptにはnull許容値はありませんが、変数タイプを強制しないため、特定の変数をnull、true、またはfalseにできるという規則を採用し、C#またはJavaのnull許容ブール値と同様の方法で使用できます。 .lang.Boolean。

まず、ブール値へのバインドの問題があります。Knockoutは、すべてのバインドされた値がデフォルトで文字列型であることを望んでいます。これについてはここここで説明します。RPNiemeyerが提供するソリューションは、次のようなカスタムバインディングを使用することです:(この例ではJS Fiddleへのリンク

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

そこで、これを出発点として使用し、このカスタムバインディングを思いつきました。うまくいくようです。このアプローチに関するコミュニティのフィードバックに興味があります。jsfiddleをチェックして、自分で試してみてください。これに関する欠点やスケーラビリティの問題はありますか?

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

1 に答える 1

3

わかりました。エクステンダーメソッドが思ったとおりに機能しなかったので、削除しました(興味があれば、編集履歴に残っています)。HTMLでオプションを指定しないように、バインディングを変更してオプションを配置するようにしました。「Null」オプションテキストを指定するオプションもあります(これを拡張して、各ラベルを設定できるようにすることができます)。

このメソッドを使用すると、オブザーバブルを標準のnull許容ブール値のように扱うことができます。HTMLは次のとおりです(注、これnullLabelは完全にオプションです)。

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

そして、ここにフィドルがあります。

于 2012-11-08T19:49:50.180 に答える