これは一般的な状況である必要があると思います。ノックアウトでこれを処理する方法について受け入れられている慣習があるかどうか疑問に思います。「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);