2013-12-09 45 views
2

我正在使用Twitter Bootstrap按鈕組以及Knockout。我覺得我忽視了一些非常簡單的事情,但是,在這種情況下,我還沒有能夠獲得checked綁定的工作。敲除檢查綁定不起作用

我有一個jsFiddle重現這裏的問題:http://jsfiddle.net/n5SBa/

下面是從小提琴代碼:

HTML

<div class="form-group"> 
    <div class="btn-group" data-toggle="buttons"> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '0'), css: { active: Score() == '0' }"> 
      <input type="radio" name="score" value="0" data-bind="checked: Score" /> 0 
     </label> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '1'), css: { active: Score() == '1' }"> 
      <input type="radio" name="score" value="1" data-bind="checked: Score" /> 1 
     </label> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '2'), css: { active: Score() == '2' }"> 
      <input type="radio" name="score" value="2" data-bind="checked: Score" /> 2 
     </label> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '3'), css: { active: Score() == '3' }"> 
      <input type="radio" name="score" value="3" data-bind="checked: Score" /> 3 
     </label> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '4'), css: { active: Score() == '4' }"> 
      <input type="radio" name="score" value="4" data-bind="checked: Score" /> 4 
     </label> 
     <label class="btn btn-primary" data-bind="click: ClickScore.bind($data, '5'), css: { active: Score() == '5' }"> 
      <input type="radio" name="score" value="5" data-bind="checked: Score" /> 5 
     </label> 
    </div> 
</div> 

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

的Javascript

function SurveyViewModel() { 
    var self = this; 

    self.Score = ko.observable(); 

    //Events 
    self.ClickScore = function (score) { 
     self.Score(score); 
    }; 

    //Computations 
    self.RecommendationLabel = ko.computed(function() { 
     if (self.Score() < 8) { 
      return "Some question?"; 
     } else { 
      return "Some other question?"; 
     } 
    }); 

    self.DOMSelectedScore = ko.computed(function() { 
     if ($('input[name=score]:checked').val()) { 
      return $('input[name=score]:checked').val(); 
     } else { 
      return 'no value!'; 
     } 
    }); 
}; 

var surveyViewModel = new SurveyViewModel(); 

ko.applyBindings(surveyViewModel); 

在這個例子中,我無法獲得實際的單選按鈕在DOM中選中,以便它可以正確提交到我的表單中。

回答

8

複選框的值是字符串("0","1"等),但是您將observable的值設置爲數字。在進行比較時,checked綁定使用嚴格的等式,並且不會將數字1等同於字符串"1"

您可以通過觀察到的值設置爲字符串解決這個問題:

data-bind="click: ClickScore.bind($data, '1')" 

http://jsfiddle.net/mbest/n5SBa/2/

+0

我其實有我的代碼設置傳遞字符串,這是我的一個錯字。即使在你連接的小提琴中,問題仍然存在(DOM選定值仍未定義) –

+0

我打開控制檯並運行$('input [name = score]:checked')',並返回正確的項目。 –

+0

我給你+1,因爲你的回答肯定有幫助。但是,我只是添加了自己的答案,因爲看起來問題比我想象的要複雜得多。 –

3

DOMSelectedScore計算觀察到的不引用任何其他可觀察到的,所以它永遠不會被重新計算。

self.DOMSelectedScore = ko.computed(function() { 
    self.Score(); // subscribe to Score, even if we don't use it. 
    var val = $('input[name=score]:checked').val(); 
    return val || 'no value!'; 
}); 

修復這個問題,看起來DOM直到函數返回後纔會更新,所以值落後於一次點擊。爲了解決這個問題,我們需要推遲,直到DOM已更新:

self.DOMSelectedScore = ko.computed(function() { 
    self.Score(); // subscribe to Score, even if we don't use it. 
    var val = $('input[name=score]:checked').val(); 
    return val || 'no value!'; 
}).extend({throttle:1}); // Wait for the DOM update to complete 

http://jsfiddle.net/n5SBa/5/


簡化與淘汰賽數字的結合,你可以定義一個擴展方法觀測:

ko.observable.fn.asString = function() { 
    var source = this; 
    if (!source._asString) { 
     source._asString = ko.computed({ 
      read: function() { 
       return String(source()); 
      }, 
      write: function (newValue) { 
       source(Number(newValue)); 
      } 
     }); 
    } 
    return source._asString; 
}; 

然後

<input type="radio" name="score" value="2" data-bind="checked: Score.asString()"/> 
+0

我有些困惑的是你的jsFiddle是如何工作的,即使它沒有傳遞字符串(就像其他回答說你需要這樣做)。 –

+0

這似乎與Twitter Bootstrap有關。如果您刪除該js文件,它將停止使用普通數字。 –

+1

沒錯。Bootstrap獨立於綁定設置複選框「checked」屬性。 –