80

在我的視圖模型中,我有一個值爲true或false的IsMale值。在Knockout JS中綁定真/假單選按鈕

在我的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需要一個字符串「真」 /「假」。所以我的問題是,我怎樣才能得到這個雙向綁定W /這個UI和模型?

+10

對於Knockout版本> = 3.0,請參閱[Natan的回答](http://stackoverflow.com/a/20764607/606662)以獲得比接受的答案建議的更簡單的渠道。 – 2014-02-07 20:37:31

回答

74

一種選擇是使用writeable computed 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   
    });   
}; 

你會綁定在你的用戶界面,如:

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

+0

看起來像一個偉大的解決方案。我使用映射插件來刷新我的虛擬機。你知道這會消滅IsMale上的ForEditing嗎? – 2012-04-12 16:32:29

+0

如果您使用映射插件,那麼您必須在映射中使用'create'回調(http://knockoutjs.com/documentation/plugins-mapping.html#customizing_object_construction_using_create),或在您的映射後添加ForEditing computed observable數據已經初始化(並且在添加新數據之後)。 – 2012-04-12 17:17:41

+25

下面是一個替代方案,它將計算出的可觀察創建推送到一個自定義綁定中,這將使其不必擔心在映射插件中處理它:http://jsfiddle.net/rniemeyer/utsvJ/ – 2012-04-12 17:25:13

10

這個工作對我來說:

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

我看到的唯一問題是,當序列化viewmodel傳遞給服務器時,您將得到可觀察(而不是布爾)的整數。你需要調用vm.IsMale(!! vm。+ IsMale());'在序列化json發送給服務器之前(以防服務器端無法正確處理) – Artem 2012-04-12 16:10:25

+0

我認爲你是對的,但是我的Javascript知識是不足。你能向我解釋一下如何!! +作品?我對語法不熟悉。 – 2012-04-12 16:40:22

+0

@ C.J。這將字符串或數字轉換爲布爾值 - chek這個http://jsfiddle.net/nickolsky/6ydLZ/,如果字符串已經布爾,它會保持它爲bool – Artem 2012-04-12 16:46:24

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

人們也可以問爲什麼不簡單地使用1和0而不是真和假... – 2013-04-29 14:05:20

+2

如果您發送json對象,它會產生差異。 – Doctor 2013-05-17 18:31:52

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

我知道這是一個古老的線程,但我有同樣的問題,並發現了一個更好的解決方案,它可能已添加到淘汰賽後,這個問題被正式答覆,所以我我們會把它留給有同樣問題的人。

當前不需要擴展程序,自定義綁定處理程序或計算機。 只需提供一個「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"/> 
+0

看起來像最好的解決方案,不爲我工作,奇怪 – ZiglioUK 2014-01-22 03:39:03

+2

看着源頭,它似乎決定使用選中的值[這裏](https://github.com/knockout/knockout/blob/master /src/binding/defaultBindings/checked.js#L16)。 'useCheckedValue'被設置爲true [如果輸入是一個無線電或值爲數組的複選框](https://github.com/knockout/knockout/blob/master/src/binding/defaultBindings/checked。 JS#L78)。另外,我正在使用Knockout 3.0。看看是否有幫助。 – Natan 2014-01-22 12:50:00

+1

是的,謝謝,我已升級到3.0.0,現在它在那裏。仍然需要包裝我的布爾值在一個字符串,因爲服務器代碼期待這些;-) – ZiglioUK 2014-01-22 21:15:02

0

您也可以使用extender所以很容易重複使用它們,以便更可觀:

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

pa提供給boolForEditing的rameter指示該值是否爲空。

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

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轉換,因爲我能夠使用不具有相同挫敗感的複選框。

0

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

使用延長你的模型,你'd做類似如下的事:

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/