【问题标题】:Binding KnockoutJS to Radio Button with computed使用计算将 KnockoutJS 绑定到单选按钮
【发布时间】:2012-04-24 02:09:53
【问题描述】:

我有一个包含一系列答案的问题。每个答案都有一个名为 isRight 的布尔属性,表示答案是否...正确。

我正在尝试为每个答案呈现一个单选按钮,并检查该答案是否正确。如果用户单击不同的按钮,则该答案变为正确。

我了解KO将checked属性绑定到一个值,并且每个单选按钮只有在单选的值与绑定值匹配时才会被检查;你不能直接绑定到 isRight。

我在问题本身上放置了一个 computedObservable,它应该可以做到这一点。它有效。问题是,我想订阅单选按钮的 change 事件,以查看何时选择了新答案(并发送 ajax 请求)。我遇到的问题是 ko 绑定未在更改处理程序中更新。似乎延迟处理程序会给我想要的东西,但我更喜欢更直接的解决方案。

而且似乎 click 事件完美运行,但每次单击单选按钮时都会触发,即使它已经被选中。

有什么方法可以确保在更改事件中更新绑定?当前代码是 ko 2.0,我也尝试过 2.1。

Full Fiddle


完整来源:

function Question() {
    this.name = "My Question";

    var i = 0;
    this.answers = ko.observableArray([
        new Answer(++i, "Answer 1", false),
        new Answer(++i, "Answer 2", true),
        new Answer(++i, "Answer 3", false)]);

    this.correctAnswer = ko.computed({
        read: function () {
            for (var i = 0, max = this.answers().length; i < max; i++)
                if (this.answers()[i].isRight())
                    return "answer-" + this.answers()[i].id();
        },
        write: function (newValue) {
            var newId = +newValue.split('-')[1];
            for (var i = 0, max = this.answers().length; i < max; i++)
                this.answers()[i].isRight(this.answers()[i].id() === newId);
        },
        owner: this
    });
}


function Answer(id, name, isRight) {
    this.id = ko.observable(id);
    this.name = ko.observable(name);
    this.isRight = ko.observable(isRight);
}

$(function () {
    ko.applyBindings(new Question());

    $(document).on("change", "input[type='radio']", function () {
        var answer = ko.dataFor(this);
        var isRight = answer.isRight();

        setTimeout(function () { alert("before = " + isRight + "  after = " + answer.isRight()); }, 1000);
    });
});

HTML:

<div data-bind="text:name"></div>
<div data-bind="foreach:answers">
    <label>
        <span data-bind="text: name"></span>
        <input type="radio" name="uniqueQuestionName" data-bind="value: 'answer-' + id(), checked:$parent.correctAnswer" />
    </label>
    <br />
</div>

【问题讨论】:

    标签: javascript jquery knockout.js


    【解决方案1】:

    除非您有特定的理由订阅“更改”事件,否则您可能需要考虑使用 manual subscription 来表示正在更改的可观察对象。这样,您可以在实际数据发生更改时收到通知。

    这是一个使用稍微不同的方法的示例:http://jsfiddle.net/rniemeyer/FvZXj/。它使用一个函数来处理设置值,它将当前答案作为第一个参数传递。然后它使用它来正确设置 isRight 和一个您可以订阅的可观察的 correctAnswer

    【讨论】:

    • 我考虑过这一点,但真实的例子有一系列问题,一些最初是绑定的,一些是动态添加的。我真的不想尝试跟踪所有问题并在添加新问题时保持订阅。我的一个想法是订阅 afterRender,但我没有看到将其链接到我的 ViewModel 之外的(非全局)函数的方法。如果有办法做到,我也许可以相当轻松地完成手动订阅。
    • 我会在根级别创建一个函数来执行您的 AJAX 请求,然后创建对每个问题的正确答案的订阅,作为创建新问题实例的自然部分。也许我不太了解您的情况,但您不需要管理任何订阅,因为它们将成为任何问题对象的一部分。不过我可能会遗漏一部分:)
    • 我明白了。我们选择将 AJAX 请求排除在我们的视图模型之外,但我们可能不得不重新考虑这个决定。不过现在,我们正在更改我们的数据库结构以匹配 KO 想要的(我们处于开发周期的早期) - 每个问题都会有一个正确的答案 ID - 简单易懂
    • 好的,感谢您一如既往的帮助。只是一个简短的问题:即使简化单选按钮以“正常方式”绑定,没有计算,只是一个普通的可观察的,仍然有 change 事件不起作用。但是,更改事件确实适用于文本框。这是有保证的,还是不确定的,只是碰巧通常有效?我们最终会放弃 dom 更改,但我想知道是否可以指望文本框在 ko 绑定更新后触发其更改事件。
    • 顺便说一句,单选按钮依赖 'click' 事件来更改它们似乎并不安全,因为我还可以通过点击控件并点击空格键来选择单选框选择它。
    猜你喜欢
    • 2016-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    • 2011-10-06
    • 2013-06-29
    • 2021-07-19
    • 2016-11-13
    相关资源
    最近更新 更多