I am working on a prototype questionnaire system. To ask customers questions on the telephone.
Using HTML, JS, KO (and Dynamic CRM as a datasource).
Note that I'm new to KO as this is day 2! - I am impressed, thought it seems to have an EVE-Online learning curve!
The questions are stored in Dynamics CRM and retrieved with OData call (returning JSON).
Some questions have child questions, so I de-normalise the original normalised OData result and setup the hierarchy in a new JSON object. Debugging over this object shows its all represented as expected. Tree like.
The problem I have is, I get an when i try to use the view to a certain depth. "Error: Unable to get property 'Value' of undefined or null reference"
I looked at this article Knockout.js Make every nested object an Observable, which seemed to be related to my problem, but retro fitting that solution into my code didnt work for me, i may have misunderstood my problem!
My view shows the first level of questions correctly, but the child questions only work up to a point. So when i try and databind this data-bind="value: adr_nextquestionyesid().adr_answertype.Value i get the null reference error shown above.
However, if I data bind this data-bind="value: adr_nextquestionyesid().adr_answertype i see "[Object object]" in the view. This to me suggests that it should be able to get the int value of adr_answertype!
The top level adr_answertype.Value bindings work fine, it just seems to be an issue as I get deeper into the object.
Here is My ViewModel & Model;
Note that the Next Questions are meant to be (and are in the JSON) actually Nested questions within the question, which as you can imagine could go arbitrarily deep
function QuestionAnswersVM() {
var self = this;
var questionDataRaw = RetrieveQuestionSet("15AF22A6-3E58-E411-B2A6-00155DFD8300", odataPath);
var questionDataOrganised = OrganiseQuestionHierarchy(questionDataRaw);
self.questions = ko.mapping.fromJS(questionDataOrganised, mapping);
};
var mapping = {
create: function (options) {
return new Question(options.data);
}
};
function Question(data) {
ko.mapping.fromJS(data, {}, this);
// Answers
this.DateTime = ko.observable(data.DateTime);
this.FreeText = ko.observable(data.FreeText)
this.YesNo = ko.observable(data.Yes);
// Next questions - trying to create nested question here
this.adr_nextquestionyesid = ko.observable(new Question(data.adr_nextquestionyesid));
}
Here is my View (with unrelated stuff removed);
particularly note the databindings within QuesionBoxIndent div which present the problem
<section data-bind="foreach: questions">
<div class="questionBox">
<span class="questionTitle"><span data-bind="text: adr_name"></span></span>
<div class="questionBody">
<label data-bind="text: adr_questionbody" />
</div>
<div data-bind="visible: adr_answertype().Value == 1">
<input data-bind="checked: YesNo" type="radio" value="true" />Yes
<input data-bind="checked: YesNo" type="radio" value="false" />No
<label class="mandatory" data-bind="visible: $data.adr_mandatory()"><b>*</b></label>
</div>
<div data-bind="visible: adr_answertype().Value == 2">
<input data-bind="value: FreeText" type="text" name="fname" />
<label class="mandatory" data-bind="visible: $data.adr_mandatory()"><b>*</b></label>
</div>
</div>
<div class="questionBoxIndent" data-bind="visible: adr_nextquestionyesid().adr_name != null">
<span class="questionTitle"><span data-bind="text: adr_nextquestionyesid().adr_name"></span></span>
<div class="questionBody">
<label data-bind="text: adr_nextquestionyesid().adr_questionbody" />
</div>
<div>
<input data-bind="value: adr_nextquestionyesid().FreeText" type="text" name="fname" />
<input data-bind="value: adr_nextquestionyesid().adr_answertype" type="text" name="fname" />
<input data-bind="value: adr_nextquestionyesid().adr_answertype.Value" type="text" name="fname" />
<label class="mandatory" data-bind="visible: adr_nextquestionyesid().adr_mandatory"><b>*</b></label>
</div>
</div>
<br />
Edit: Having spent another day on it, i thought i had cracked it using the suggestion of Sergiu, to use the mapping plugin. I got that to map eventually, but seemingly it doesnt expose the depth which i thought it would. Basically, when trying to access the value on the adr_answertype of the nested question, i get the same "Error: Unable to get property 'Value' of undefined or null reference". I tried all sorts of variations of view syntax to get access to the Value. Even though its definitely there when looking at the original mapped object with a debugger. Maybe I should look to build the model completely manually, that will be a separate stream of research, my reading only shows me how to declare the top level model!
Many thanks in advance all!
Peace