【问题标题】:Knockout checked binding not working淘汰赛检查绑定不起作用
【发布时间】:2013-12-27 07:21:57
【问题描述】:

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

【问题讨论】:

    标签: javascript twitter-bootstrap knockout.js


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我确实有我的代码设置来传递字符串,这是我的一个错字。即使在您链接的小提琴中,问题仍然存在(DOM 选择的值仍然未定义)
    • 我打开控制台并运行$('input[name=score]:checked'),它返回了正确的项目。
    • 我给你 +1 是因为你的回答肯定很有帮助。但是,我添加自己的答案只是因为看起来这个问题比我想象的要复杂一些。
    【解决方案2】:

    DOMSelectedScore 计算的 observable 不引用任何其他 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/


    为了简化数字与敲除的绑定,您可以为 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()"/>
    

    【讨论】:

    • 让我有点困惑的是你的 jsFiddle 是如何工作的,即使它没有传入字符串(就像另一个答案说你需要做的那样)。
    • 好像跟 Twitter Bootstrap 有关系。如果您删除该 js 文件,它将停止使用纯数字。
    • 没错。 Bootstrap 独立于绑定设置复选框的 checked 属性。
    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 2015-12-27
    • 1970-01-01
    • 2014-03-30
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 2013-03-01
    相关资源
    最近更新 更多