I have a form with a numer of questions. Each question has a number of answers. At the form level I would like to create some computed observables like total score and number of questions. The formmodel, questionsmodel and answermodel are created in the same way. The questionsmodel is 'aware' of the answers. It lets me create computed observables like the number of answers or maximum points.
My problem is the form model which doesn't recognize the questions-array. I can count the numer of answers in each question, but not the number of questions in the form. Is there something wrong with my models or should I investigate my data?
function formViewModel(data) {
var self = this;
var mapping = {
'questions': {
create: function (options) {
return new questionsViewModel(options.data);
}
}
};
var model = ko.mapping.fromJSON(data, mapping, self);
model.numberOfQuestions = ko.computed(function () {
return self.questions().length; // error: self.questions() is not a function
});
return model;
}
function questionsViewModel(data) {
var self = this;
var mapping = {
'answers': {
create: function (options) {
return new answersViewModel(options.data);
}
}
};
var model = ko.mapping.fromJS(data, mapping, self);
model.numberOfAnswers = ko.computed(function () {
return self.answers().length; // no problem
});
return model;
}
function answersViewModel(data) {
var self = this;
var mapping = {};
var model = ko.mapping.fromJS(data, mapping, self);
return model;
}
I think you are trying to get the length of questions before it has been fully instantiated - can you try to change your computed to the following -
model.numberOfQuestions = ko.computed(function () {
if (!self.questions()) {return 0;}
return self.questions().length; // error: self.questions() is not a function
});
but also it looks like you may have some scope issues -
function formViewModel(data) {
var self = this;
self.mapping = {
// do stuff
};
}
Check out this answer for more info on properly establishing scope in a nested map. I bet if you console.log(self) before your self.questions().length it isn't what you are looking for, or it isn't yet at least.
Map JSON data to Knockout observableArray with specific view model type