KnockoutJSのラジオボタンにtrue / falseをバインドする


84

私のビューモデルには、trueまたはfalseの値を持つIsMale値があります。

私の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とモデルでこの双方向バインディングを取得できますか?


10
ノックアウトバージョン> = 3.0の場合、受け入れられた回答で提案されているよりも簡単な解決策については、Natanの回答を参照してください。
Markus Pscheidt 2014

回答:


81

1つのオプションは、書き込み可能な計算されたobservableを使用することです。

この場合、書き込み可能な計算されたオブザーバブルをオブザーバブルの「サブオブザーバブル」にするのが良いオプションだと思います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        
    });          
};

次のように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>

サンプル:http//jsfiddle.net/rniemeyer/Pjdse/


素晴らしい解決策のようです。マッピングプラグインを使用してVMを更新します。IsMaleのForEditingを一掃することを知っていますか?
CJ

26
計算された監視
RP Niemeyer

2
すべてのオブジェクトに観察結合を使用して代わりの作成に+1
グレッグエニスを

1
@RPNiemeyerは間違いなく行く方法です。
アンドリュー

1
@RPNiemeyerありがとう!コメントのそのフィドルは私のために働いたものです。
SFlagg 2015

128

これは古いスレッドですが、同じ問題が発生していて、この質問に正式に回答した後にノックアウトに追加された可能性のあるはるかに優れた解決策を見つけたので、同じ問題を抱えている人に任せます。

現在、エクステンダー、カスタムバインディングハンドラー、または計算機は必要ありません。「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"/>

2
ソースを見ると、ここでチェックした値を使用することを決定しているようです入力がラジオまたは値を配列として持つチェックボックスの場合、「useCheckedValue」はtrueに設定されます。また、Knockout3.0を使用しています。それが役立つかどうかを確認してください。
ナタン2014年

1
ええ、ありがとう、私は3.0.0にアップグレードしました、そして今それはそこにあります。サーバーコードがブール値を予期していたため、ブール値を文字列でラップする必要があります;-)
ZiglioUK 2014年

良い情報。2つの追加ポイント:(1)v3.0より前のノックアウトでは、valueバインディング、次にcheckedバインディングを(この順序で)使用できましたが、3.0checkedValueでは、バインディングの代わりにバインディングを使用する必要がありましたvalue。(2)事前v3.0には必要な好き嫌いたvalue先行するバインディングchecked私はあなたが置くならば、物事はまた、すべてのシナリオでV3.0に良い仕事かもしれないと感じていて、正しく機能への結合をcheckedValueする前にバインディングcheckedバインディングなどは、それらはドキュメントに表示されます。
ジェイソンフランク

@ZiglioNZこれが失敗する可能性のある1つの方法は、checkedセッター(またはそれに依存するもの)がエラーを発生させた場合です-その後、正しいチェックボックスがチェックされません
Simon_Weaver 2014

バージョン3.4を使用していますが、それを機能させるには、value = "true"以上を入力する必要があります。
wirble 2016年

11

これは私のために働きます:

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>

私が見る唯一の問題は、viewmodelをシリアル化してサーバーに渡すときに、(ブール値ではなく)observableの整数を取得することです。vm.IsMale(!!vm.+IsMale());サーバーに送信するためにjsonをシリアル化する前に呼び出す必要があります(サーバー側が適切に処理できない場合)
Artem 2012

あなたは正しいと思いますが、私のJavascriptの知識が不足しています。!! +のしくみを教えていただけますか?私はその構文に精通していません。
CJ

1
@CJこれは文字列または数値をブール値に変換します-このjsfiddle.net/nickolsky/6ydLZをチェックします。文字列がすでにブール値である場合はブール値として保持されます
Artem

どうもありがとう。これも素晴らしい解決策だと思います。
CJ

1
ただし、両方の方法で機能するわけではありません。ロード時にラジオボタンはチェックされません。
ミカエルÖstberg

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

1

あなたがいることを把握したら、ラジオボタンの初期マッチが唯一の文字列にマッチしたい文字列に値を設定したい、それは単に文字列にあなたの初期値を変換の問題です。私はこれをInt値と戦わなければなりませんでした。

オブザーバブルを設定した後、値を文字列に変換すると、KOはそこから魔法を実行します。個々の行でマッピングする場合は、それらの行で変換を行います。

サンプルコードでは、Jsonを使用してモデル全体を1つのコマンドでマッピングしています。次に、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>

開発中は、Webページの下部にある「すべてを画面にダンプ」を使用します。

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

ここでは、データ値であり、

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

そして、

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

私のプロジェクトでは、同じ欲求不満のないチェックボックスを使用できるため、Boolsを変換する必要はありませんでした。


0

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>

2
jsonオブジェクトを送信する場合は、違いが生じます。
医師

0

エクステンダーを使用して、より多くの観測量に再利用することも簡単にできます。

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値がNULLである可能性があるかどうかを示すために提供されるパラメーター。

http://jsfiddle.net/G8qs9/1/を参照してください


0

3.0より前の古いバージョンのノックアウトについて多くの調査を行った後、おそらく2つの最良のオプションがあります

次のようなノックアウトエクステンダーを作成します

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/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.