Knockout检查绑定无法正常工作

时间:2013-12-09 23:47:00

标签: javascript twitter-bootstrap knockout.js

我正在使用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中选择实际的单选按钮,以便可以在我的表单中正确提交。

2 个答案:

答案 0 :(得分:9)

复选框的值是字符串("0""1"等),但您要将observable的值设置为数字。 checked绑定在进行比较时使用严格相等,并且不将数字1视为等于字符串"1"

您可以通过将observable的值设置为字符串来解决此问题:

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

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

答案 1 :(得分:4)

DOMSelectedScore计算的observable不引用任何其他可观察对象,因此永远不会重新计算。

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/


为简化数字与knockout的绑定,您可以为observables定义扩展方法:

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()"/>