在 Knokout JS 中将 true/false 绑定到单选按钮

在我的视图模型中,我有一个 IsMen 值,它的值为 true 或 false。

在我的 UI 中,我希望将它绑定到以下单选按钮:

<label>Male
<input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
</label>

我认为问题在于 checked期望字符串为“ true”/“ false”。所以我的问题是,我怎样才能得到这个 UI 和模型的双向绑定?

50817 次浏览

这对我有用:

Http://jsfiddle.net/zrbul/291/

<label>Male
<input type="radio" name="IsMale" value="1" data-bind="checked:IsMale"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="0" data-bind="checked:IsMale"/>
</label>

一种选择是使用 可写的计算机可观测的

在这种情况下,我认为一个不错的选择是使可写的计算可观察的“次观察”的 IsMale可观察。您的视图模型应该是这样的:

var ViewModel = function() {
this.IsMale = ko.observable(true);


this.IsMale.ForEditing = ko.computed({
read: function() {
return this.IsMale().toString();
},
write: function(newValue) {
this.IsMale(newValue === "true");
},
owner: this
});
};

你可以把它绑定在你的用户界面上,比如:

<label>Male
<input type="radio" name="IsMale" value="true" data-bind="checked:IsMale.ForEditing"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="false" data-bind="checked:IsMale.ForEditing"/>
</label>

样本: http://jsfiddle.net/rniemeyer/Pjdse/

为什么不简单地用真和假来代替1和0呢?

 <label>Male
<input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
</label>
ko.bindingHandlers['radiobuttonyesno'] = {
'init': function (element, valueAccessor, allBindingsAccessor) {
var stateHandler = function (property, allBindingsAccessor, key, value, checkIfDifferent) {
if (!property || !ko.isObservable(property)) {
var propWriters = allBindingsAccessor()['_ko_property_writers'];
if (propWriters && propWriters[key])
propWriters[key](value);
} else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
property(value);
}
};


var updateHandler = function () {
var valueToWrite;


if ((element.type == "radio") && (element.checked)) {
valueToWrite = element.value;
} else {
return; // "radiobuttonyesno" binding only responds to selected radio buttons
}


valueToWrite = (valueToWrite === "True") ? true : false;


var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue); //can be true of false


stateHandler(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
};
ko.utils.registerEventHandler(element, "click", updateHandler);


// IE 6 won't allow radio buttons to be selected unless they have a name
if ((element.type == "radio") && !element.name)
ko.bindingHandlers['uniqueName']['init'](element, function () { return true });
},
'update': function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());


value = value ? "True" : "False";


if (element.type == "radio") {
element.checked = (element.value == value);
}
}
};

使用这个活页夹,而不是创建愚蠢的 KO 计算观察值。

例如:

<label>Male
<input type="radio" name="IsMale" value="True" data-bind="radiobuttonyesno:IsMale"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="False" data-bind="radiobuttonyesno:IsMale"/>
</label>

我知道这是一个老线程,但我有同样的问题,并发现了一个更好的解决方案,可能被添加到淘汰后,这个问题正式回答,所以我只是留给人们与同样的问题。

目前不需要扩展程序、自定义绑定处理程序或计算机。 只需提供一个“ checkedValue”选项,它将使用该选项而不是 html‘ value’属性,并且可以通过该属性传递任何 javascript 值。

<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: true"/>
<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: false"/>

或者:

<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 1"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 2"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 3"/>

你也可以使用 扩张器,这样就可以很容易地重复使用它们以获得更多的可观测数据:

ko.extenders.boolForEditing = function (target, allowNull) {
var result = ko.computed({
read: function () {
var current = target();
var newValue = null;
if (current === undefined || current === null || current === '') {
if (!allowNull) {
newValue = 'false';
}
} else {
newValue = current ? 'true' : 'false';
}
return newValue;
},
write: function (newValue) {
var current = target();
var valueToWrite = null;
if (newValue === undefined || newValue === null || newValue === '') {
if (!allowNull) {
valueToWrite = false;
}
} else {
valueToWrite = newValue === 'true';
}
// only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({
notify: 'always'
});


result(target());


return result;
};

然后像这样使用它:

this.IsMale.forEditing = this.IsMale.extend({boolForEditing: true});

提供给 boolForEditing的参数指示该值是否可以为空。

参见 http://jsfiddle.net/G8qs9/1/

一旦你算出了 单选按钮的初始匹配只想匹配字符串并且想要将值设置为一个字符串,它只是一个将初始值转换为字符串的问题。我必须用 Int 值来解决这个问题。

在你设置好你的观察值之后,将值转换成字符串,KO 将从那里施展它的魔法。如果要映射单个行,请在这些行中执行转换。

在示例代码中,我使用 Json 在一个命令中映射整个模型。 然后让 Razor 在转换的引号之间插入值。

script type="text/javascript">
KoSetup.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
KoSetup.ViewModel.ManifestEntered("@Model.ManifestEntered");       //Bool
KoSetup.ViewModel.OrderStatusID("@Model.OrderStatusID");           //Int
</script>

在开发过程中,我在网页的底部使用了“转储到屏幕上”。

<h4>Debug</h4>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

这是数据值 之前

"OrderStatusID": 6,
"ManifestEntered": true,

还有 之后

"OrderStatusID": "6",
"ManifestEntered": "True",

在我的项目中,我不需要转换 Bools,因为我可以使用一个复选框,不会遇到同样的挫折。

在对3.0之前的老版本淘汰赛做了大量研究之后,可能有两个最佳选择

创建一个淘汰扩展程序,如

ko.extenders["booleanValue"] = function (target) {
target.formattedValue = ko.computed({
read: function () {
if (target() === true) return "True";
else if (target() === false) return "False";
},
write: function (newValue) {
if (newValue) {
if (newValue === "False") target(false);
else if (newValue === "True") target(true);
}
}
});


target.formattedValue(target());
return target;
};

要在模型上使用扩展程序,需要执行以下操作:

function Order() {
this.wantsFries= ko.observable(false).extend({ booleanValue: null });
}


<span>Do you want fries with that?</span>
<label>
<input type="radio" name="question" value="True"
data-bind="value: wantsFries.formattedValue" /> Yes
</label>
<label>
<input type="radio" name="question" value="False"
data-bind="value: wantsFries.formattedValue" /> No
</label>

来源: http://www.timlabonne.com/2013/02/building-a-knockout-js-extender-for-boolean-values/