Binding KnockoutJS to Radio Button with computed

匿名 (未验证) 提交于 2019-12-03 10:10:24

问题:

I have a question with an array of answers. Each answer has a boolean property called isRight, which represents whether the answer is...right.

I'm trying to render a radio button for each answer, and have it be checked if that answer is right. If the user clicks a different button, that answer becomes correct.

I understand that KO binds the checked property to a value, and each radio button will only be checked if the radio's value matches the bound value; you can't just bind directly to isRight.

I put a computedObservable on the question itself, which should do all that. And it works. The problem is, I want to subscribe to the change event of the radio button, to see when a new answer is selected (and send an ajax request). The problem I'm having is that the ko binding is not updated in the change handler. It seems putting a delay in the handler will give me what I want, but I'd prefer a more direct solution.

And it seems the click event works perfectly, but that'll fire each time a radio button is clicked, even if it's already checked.

Is there any way to ensure that the binding is updated in the change event? Current code is ko 2.0, and I've also tried 2.1.

Full Fiddle


Full Source:

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> 

回答1:

Unless you have a specific reason to subscribe to the "change" event, you might want to consider using a manual subscription to an observable that is changing. This way you can be notified whenever the actual data is changed.

Here is a sample that uses a slightly different approach: http://jsfiddle.net/rniemeyer/FvZXj/. It uses a function to handle setting the value, which passes the current answer as the first argument. It then uses that to properly set isRight and an observable correctAnswer that you could subscribe against.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!