Javascript 将真/假绑定到 Knockout JS 中的单选按钮

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10127001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:59:00  来源:igfitidea点击:

Binding true / false to radio buttons in Knockout JS

javascriptknockout.jsknockout-mapping-pluginknockout-2.0

提问by C.J.

In my view model I have a IsMale value that has the value true or false.

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

In my UI I wish to bind it to the following radio buttons:

在我的 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>

The problem I think is checkedexpects a string "true" / "false". So my question is, how can I get this 2-way binding w/ this UI and model?

我认为的问题是checked需要一个字符串“真”/“假”。所以我的问题是,如何使用此 UI 和模型获得这种 2 向绑定?

采纳答案by RP Niemeyer

One option is to use a writeable computed observable.

一种选择是使用可写的计算 observable

In this case, I think that a nice option is to make the writeable computed observable a "sub-observable" of your IsMaleobservable. Your view model would look like:

在这种情况下,我认为一个不错的选择是使可写的计算 observable 成为您的IsMaleobservable的“sub-observable” 。您的视图模型如下所示:

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

You would bind it in your UI like:

您可以将它绑定到您的 UI 中,例如:

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

Sample: http://jsfiddle.net/rniemeyer/Pjdse/

示例:http: //jsfiddle.net/rniemeyer/Pjdse/

回答by Natan

I know this is an old thread, but I was having the same problem and found out a much better solution that was probably added to knockout after this question was officially answered, so I'll just leave it for people with the same problem.

我知道这是一个旧线程,但我遇到了同样的问题,并找到了一个更好的解决方案,在正式回答这个问题后可能会添加到淘汰赛中,所以我会把它留给有同样问题的人。

Currently there is no need for extenders, custom binding handlers or computeds. Just provide a "checkedValue" option, it will use that instead of the html 'value' attribute, and with that you can pass any javascript value.

目前不需要扩展器、自定义绑定处理程序或计算器。只需提供一个“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"/>

Or:

或者:

<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"/>

回答by Artem

This works for me:

这对我有用:

http://jsfiddle.net/zrBuL/291/

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>

回答by Greg Little

Once you figure out that the initial match for the radio button wants to match only a stringand wants to set the value to a string, it is simply a matter of converting your initial value to string.I had to fight this with Int values.

一旦您发现单选按钮的初始匹配项只想匹配一个字符串并且想将该值设置为一个字符串,那么只需将您的初始值转换为字符串即可。我不得不用 Int 值来解决这个问题。

After you have setup your observables, convert the value to string and KO will do its magic from there. If you are mapping with individual lines, do the conversion in those lines.

设置完 observable 后,将值转换为字符串,KO 将从那里开始发挥它的魔力。如果您使用单独的行进行映射,请在这些行中进行转换。

In the example code, I'm using Json to map the whole Model in a single command. Then letting Razor insert the value between the quotes for the conversion.

在示例代码中,我使用 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>

I use a "Dump it all to the screen" at the bottom of my web page during development.

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

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

Here are the data values, Before

这是数据值,之前

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

and, After

并且,经过

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

In my project, I didn't need to convert Bools, because I'm able to use a checkbox that doesn't have the same frustration.

在我的项目中,我不需要转换 Bools,因为我能够使用一个没有相同挫折的复选框。

回答by KurtJ

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

Use this binder instead of creating stupid ko computed observables.

使用这个活页夹而不是创建愚蠢的 ko 计算 observables。

Example:

例子:

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

回答by Anshul Nigam

After doing lot of research for older version of knockout prior to 3.0 there are possibly two best options

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

Create a knockout extender like

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

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

To use the extender on your model, you'd do something like the following:

要在您的模型上使用扩展器,您需要执行以下操作:

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>

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

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

回答by sroes

You can also use an extenderso it's easy to reuse them for more observables:

您还可以使用扩展器,以便可以轻松地将它们重用于更多可观察对象:

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

Then use it like this:

然后像这样使用它:

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

The parameter provided to boolForEditingindicates whether the value may be null.

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

See http://jsfiddle.net/G8qs9/1/

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

回答by Doctor

Why not simply true and false instead of 1 and 0?

为什么不简单地用 true 和 false 而不是 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>