2012-11-16 128 views
3

我有相同的複選框和單選按鈕的數據結構。當檢查複選框時,它們會返回正確的布爾值('selected'變量)。KnockoutJS單選按鈕不會像複選框一樣變化

但是,當我檢查單選按鈕時,'選擇'總是更改爲'值'(整數)。

而且單選按鈕沒有得到 「選中」 在開始的時候,即使 '選擇' ==真

的Javascript:

function attributeValueViewModel(data) { 
    var self = this; 
    self.id = ko.observable(data.id); 
    self.attributeID = ko.observable(data.attributeID); 
    self.value = ko.observable(data.value); 
    self.chosen = ko.observable(data.chosen); 
} 

function viewModel() { 
    var self = this; 
    self.attributeValues1 = ko.observableArray([]); 
    self.attributeValues2 = ko.observableArray([]); 
    self.addToList = function(data) { 
     ko.utils.arrayForEach(data, function(item) {   
      self.attributeValues1.push(new attributeValueViewModel(item)); 
      self.attributeValues2.push(new attributeValueViewModel(item)); 
     }); 
    }; 
} 

var arr = [ 
    { 
     "id": 55, 
     "attributeID": 28, 
     "value": "Yes", 
     "chosen": false, 
    }, 
    { 
     "id": 56, 
     "attributeID": 28, 
     "value": "No", 
     "chosen": true, 
    }, 
    { 
     "id": 62, 
     "attributeID": 28, 
     "value": "Maybe", 
     "chosen": false, 
    } 
]; 

var vm = new viewModel(); 
ko.applyBindings(vm); 
vm.addToList(arr); 

HTML

<b>Checkbox:</b> 
<div id="test1"> 
    <span data-bind="foreach: attributeValues1()"> 
    <input type="checkbox" data-bind="value: id(), checked: chosen, attr: { name: 'test1' }" /> 
    <span data-bind="text: value()"></span> 
    <span data-bind="text: chosen()"></span> 
    </span> 
</div> 
<br /> 
<b>Radio:</b> 
<div id="test2"> 
    <span data-bind="foreach: attributeValues2()"> 
    <input type="radio" data-bind="value: id(), checked: chosen, attr: { name: 'test2' }" /> 
    <span data-bind="text: value()"></span> 
    <span data-bind="text: chosen()"></span> 
    </span> 
</div>​ 

這是我的小提琴:http://jsfiddle.net/SN7Vn/1/

你能解釋這種行爲,爲什麼單選按鈕不更新布爾(就像複選框一樣)?

回答

5

複選框和單選按鈕的行爲彼此不同。當一個觀測值綁定到checked綁定(而不是數組)時,它們的行爲特別不同。

對於複選框,它將始終是一個布爾值,指示它是否被選中。簡單。如果一個數組,value將被添加或從數組中刪除。

但是,對於單選按鈕,它將是分配給單選按鈕的值。對於單個觀測值,它只會被視爲檢查它所綁定的值是否等於該值。在你的情況下,你的值綁定到id,所以只會在chosen值等於相應的ID時纔會響應。對於數組,它將向數組添加/刪除值。

由於沒有別的改變chosen的相應屬性的值,它仍然是相同的

我優化了你的例子來說明一點的價值是如何影響的選中狀態。 Updated fiddle

這一切都拼寫出來in the documentation,仔細看看它。


如果您希望它的工作方式類似於複選框,它需要一些工作才能正確使用。由於綁定是如何工作的以及它們的順序依賴性如何導致問題,我有這種代碼會覺得有點脆弱。你可以試試看,我只是不確定這是多麼強大。

爲了達到這個目的,您需要一個可觀察值來跟蹤實際選中單選按鈕的實際更改。然後,您可以訂閱該可觀察項的更改以更新您選擇的可觀察項。

ko.bindingHandlers.radiochecked = { 
    init: function (element, valueAccessor, allBindingsAccessor) { 
     // the checked binding depends on the element having an initial value 
     // we need to allow bindings that potentially set it to be applied first 
     setTimeout(function() { 
      var options = ko.utils.unwrapObservable(valueAccessor()); 
      if (options.checked()) { 
       options.selected(element.value); 
      } 
      options.selected.subscribe(function (newValue) { 
       options.checked(newValue === element.value); 
      }); 
      ko.applyBindingsToNode(element, { checked: options.selected }); 
     }, 0); 
    } 
}; 

然後將其綁定到你的單選按鈕:

<input type="radio" data-bind=" 
    value: id, 
    radiochecked: { 
     'checked': chosen, 
     'selected': $root.attributeValues2.selected 
    }, 
    attr: { name: 'test2' }" /> 

Demo

+0

謝謝您的回答。我想要的就是「選擇」是否爲「複選框」,是正確/錯誤 - 就像複選框一樣。另外,如果我添加了一個下拉列表,我希望該值是true/false,無論該值是否在列表中被選中。這可能嗎? – Gaui

+0

有可能獲得該行爲,但需要一些工作。 –

+0

我有一個可能的解決方案來做你想做的事情,但由於應用綁定的未知順序以及'checked'綁定的工作方式,它似乎非常脆弱。因爲這個,我有點猶豫分享這個。 –

1

這也可能有幫助。下面的綁定將採用一組單選按鈕,在更改其中一個單選按鈕時,將組中其餘部分的觀察值設置爲特定值(null,false,0,...)

就目前而言,它要求observable的值爲true/false,以便它能夠選擇正確的單選按鈕。

ko.bindingHandlers.checkedRadio = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     $(element).change(function() { 
      //Get all radio buttons int he group 
      var group = $(element).attr('name'); 
      var radios = $('input[type="radio"][name="' + group + '"]').not($(element)); 

      //Reset all values for other radio buttons in this group 
      $.each(radios, function (i, radio) { 
       var $r = $(radio); 
       if (!$r.prop('checked')) { 
        var data = ko.dataFor(radio); 
        data[allBindingsAccessor().checkedRadioProperty](allBindingsAccessor().checkedRadioValue); 
       } 
      }); 

      //Update bound data 
      var value = valueAccessor(); 
      var checked = $(element).prop('checked'); 
      value(checked); 
     }); 

     //Select radio button based on bound data 
     var value = unwrap(valueAccessor()); 
     $(element).prop('checked', value); 
    } 
}; 

要使用綁定你可以是這樣的:

<input type="radio" value="true" data-bind="name: 'option-group-' + attributeID() }, checkedRadio: chosen, checkedRadioProperty: 'chosen', checkedRadioValue: false" />