2013-12-09 8 views
2

Я использую группу кнопок Bootstrap Twitter вместе с Knockout. Я чувствую, что я пропускаю что-то очень простое, но мне не удалось получить привязку checked, работающую в этом экземпляре.Knockout checked binding not working

У меня есть 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" и т. Д.), Но вы устанавливаете значение наблюдаемого на число. Связывание 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 устанавливает флажок «проверено» независимо от привязок. –