Reputation: 181
I'm attempting to build a tree like structure with one main json call that grabs a list of studies. From this it uses the studyId's in yet another json call. This query will not always have data. How do i handle undefined? However, that might not be my main issue as I have been unable to get the this to work correctly. I'll be keeping an eye on this post so feel free to ask questions I should respond reasonably fast. Thanks!
//=====================================================\
function StudyInfo(data) {
this.StudyId = ko.observable(data.StudyId);
this.Name = ko.observable(data.Name);
this.Title = ko.observable(data.Title);
this.Samples = ko.observableArray([]); // this field is not mapped in lazy load.
}
function SampleInfo(data) {
this.Name = ko.observable(data.Name);
}
function viewModel() {
var self = this;
self.Studies = ko.observableArray([]);
var request = $.getJSON("/api/studies");
request.done(function (data) {
var mappedStudies = $.map(data, function (item) {
// now get study
var study = new StudyInfo(item);
study.Samples(self.getSamples(study.StudyId));
return study;
});
self.Studies(mappedStudies);
});
request.fail(function (data) {
// error stuff not important in example
});
self.getSamples = function (StudyId) {
var request = $.getJSON("/api/samples/"+StudyId());
request.done(function (data) {
var mappedSamples = $.map(data, function (item) {
var sample = new SampleInfo(item);
return sample;
});
return mappedSamples;
});
request.fail(function (data) {
// error stuff
});
};
}
//=====================================================\
<!--- list that resembles a tree -->
<ul data-bind="foreach: Studies()">
<li><a><span data-bind="text: Name"></span></a>
<ul data-bind="foreach: Samples">
<li><a><span data-bind="Title"></span></a>
</ul>
</li>
<ul>
//=====================================================\
Upvotes: 1
Views: 841
Reputation: 3202
Try this for your viewmodel, based on antishok's comment:
function viewModel() {
var self = this;
self.Studies = ko.observableArray([]);
$.getJSON("/api/studies", function(allStudiesData) {
$.each(allStudiesData, function (index, studyData) {
var study = new StudyInfo(studyData);
// The getJSON call returns immediately and the $.each loop will
// loop around to the next study in allStudiesData. Later on,
// each time the web server returns data to us from each of the samples
// calls, the function(allSamplesData) will be called
$.getJSON("/api/samples/"+studyData.StudyId, function(allSamplesData) {
var mappedSamples = $.map(allSamplesData, function (sampleData) {
var sample = new SampleInfo(sampleData);
return sample;
});
study.Samples(mappedSamples);
// If you put this push call outside the $.getJSON, the push would
// happen before the mappedSamples were added to the study
self.Studies.push(study);
});
});
});
return self;
}
However, I would suggest a different approach. I would recommend putting all of this data together on the server, so that you can make a single call to /api/studieswithsamples and get a big chunk of JSON back. Then your code could be simplified, but the real benefit is that it would only require a single HTTP call to the server to get all of your code back. This could help to improve the page load time.
P.S. Don't forget to return self from the viewmodel.
Upvotes: 1