【发布时间】:2016-03-18 03:49:20
【问题描述】:
这是我的第一个问题,请原谅发布问题的任何错误。
我的问题可能看起来与 Build knockout model and view dynamically, radio buttons not being set
根据我的研究,上述问题与我的问题非常接近,但仍然无法解决。
在我的要求中,每个问题都有多个单选按钮作为选项,并且还有上一个和下一个导航按钮。 问题和选择是动态构建的,用户对问题所做的选择不会被 viewmodel 属性 self.current_question.response 捕获。
以下是我的观点sn-p
<div id="questionpage" data-role="page" data-theme="c">
<div data-role="header" data-theme="c">
<h1>Question <span data-bind="text: current_question().queNo"></span></h1>
</div><!-- /header -->
<!-- inputs -->
<div id="inputs" data-role="content" data-theme="c">
<a id="prevbtn" href="#question" data-icon="arrow-l" data-bind="click: $root.prev, visible: hasPrev()" data-role="button" data-inline="true">Prev</a>
<a id="nextbtn" href="#question" data-icon="arrow-r" data-bind="click: $root.next, visible: hasNext()" data-role="button" data-inline="true">Next</a>
<a id="completebtn" href="#question" data-icon="check" data-bind="click: $root.submit, visible: !hasNext()" data-role="button" data-inline="true">Submit</a>
<p data-bind="text: current_question().queText"></p>
<div id="inputdiv">
</div>
</div><!-- /content -->
</div><!-- /page -->
下面是我的 Viewmodel 的 sn-p
// Question response object
function QuestionResponse(stuId, examQueId,selAns)
{
var self=this;
self.Student__c=stuId;
self.Exam_Question__c=examQueId;
self.Selected_Answer__c=selAns;
}
// Question object
function Question()
{
var self=this;
self.response=ko.observable('');
self.options=ko.observableArray();
}
function Question(id, queNo, queText, response, queChA, queChB, queChC, queChD, queChE)
{
var self=this;
self.id=id;
self.queNo=queNo;
self.queText=queText;
self.response=ko.observable(response);
self.options=ko.observableArray();
//self.checked=ko.observableArray();
// helper function to add an option
self.addOption = function(option)
{
if (null!=option)
{
self.options().push(option);
}
}
self.addOption(queChA);
self.addOption(queChB);
self.addOption(queChC);
self.addOption(queChD);
self.addOption(queChE);
}
function ExamViewModel()
{
var self=this;
// initialise variables to default observables
// self.question_response=ko.observable(new QuestionResponse());
self.current_question=ko.observable(new Question());
self.current_question_no=0;
self.email=ko.observable('Your email id');
self.questions=ko.observableArray();
self.studentId;
self.errorMsg=ko.observable('');
self.completeMsg=ko.observable('');
self.hasPrevious=ko.observable();
self.hasNext=ko.observable(false);
self.hasPrev=ko.observable(false);
// function executed when the user clicks the 'next' button
self.next=function()
{
$.mobile.loading( 'show', { theme: "a", text: "Loading", textVisible: true });
// advance to the next question
self.current_question_no++;
self.current_question(self.questions()[self.current_question_no]());
// setup previous/next buttons
self.hasPrev(true);
self.hasNext(self.current_question_no<self.questions().length-1);
// add the input markup
self.addInput();
$.mobile.loading('hide');
}
// function executed when the user clicks the 'prev' button - could refactor
// some of this and the next function into a common helper
self.prev=function()
{
$.mobile.loading( 'show', { theme: "a", text: "Loading", textVisible: true });
//alert('in prev '+self.current_question().response);
self.current_question_no--;
self.current_question(self.questions()[self.current_question_no]());
self.hasPrev(self.current_question_no!=0);
self.hasNext(true);
self.addInput();
$.mobile.loading('hide');
}
// callback for the JavaScript remoting call
self.responseCB=function(record, event)
{
if ( (!event) || (event.status) )
{
$.each(record,
function()
{
var question=new ko.observable(new Question(
this.Id, this.Exam_Question_Number__c, this.Question__r.Question_Text__c,'',
this.Question__r.ChoiceA__c, this.Question__r.ChoiceB__c, this.Question__r.ChoiceC__c,
this.Question__r.ChoiceD__c,this.Question__r.ChoiceE__c));
self.questions.push(question);
// if the current question is empty, set it to this question
if (typeof self.current_question().queText === 'undefined')
{
self.current_question(question());
}
});
// setup whether to display the next button
if (self.questions().length>1)
{
self.hasNext(true);
}
// add the input markup
self.addInput();
}
else if (event.type === 'exception')
{
self.error(event.message);
}
}
// add the appropriate input markup
self.addInput=function()
{
self.addRadioInput();
}
self.addRadioInput=function()
{
$('#inputdiv').html(
'<div id="radio" data-bind="value: $root.current_question.response">' +
' <fieldset id="radiocontrol" data-role="controlgroup">' +
' <' + // Visualforce will break the comment that encloses the containerless element, so split over two lines
'!-- ko foreach: current_question().options --> ' +
' <input name="radio-options" type="radio" data-bind="value: $data, checked: $root.current_question.response, attr: {id:\'rb_\' + $index() }"></input> ' +
' <label data-bind="attr:{for : \'rb_\' + $index() }, text: $data"></label> ' +
' <' +
'!-- /ko --> ' +
' </fieldset> ' +
'</div> ');
// bind the new markup to the viewmodel
ko.applyBindings(viewModel, $('#radio')[0]);
// trigger JQM to enhance the newly created radio button div
$('#radio').trigger('create');
}
}
尝试了多个选项,但无法了解我的代码有什么问题。非常感谢任何帮助。
【问题讨论】:
-
问题是您在视图模型中使用了 jQuery,这意味着您没有正确地建模视图。如果没有看到您的单选按钮 HTML 和绑定,我们无法理解为什么您没有设置您选择的值。
-
单选按钮 HTML 是在 viewmodel 函数 self.addRadioInput 中动态构建的,单选按钮插入的 HTML div 标签为
<div id="inputdiv"> </div>。如果我遗漏了什么,请告诉我。 -
通过 jQuery 插入代码是错误的做法。 Knockout 可以处理动态创建元素。您在单选按钮上的绑定似乎适合设置
response。 -
为什么在
div#radio上有一个value绑定? -
是的,
value不需要绑定div#radio,但我正在尝试您建议的方法。
标签: javascript jquery-mobile knockout.js radio-button