Reputation: 6020
I've thrown together a jsFiddle to try and demonstrate what I'm trying to achieve (reflects third attempt so far).
I've just started playing around with KnockoutJS and I'm a little stumped. Here's what I want to do.
I have an asmx method that returns a JSON string, which is the following objects deserialized (most properties omitted for brevity):
class Template
{
public int Id { get; set; }
public string Name { get; set; }
public List<Group> Groups { get; set; }
}
class Group
{
public string Name { get; set; }
public List<Question> Questions { get; set; }
}
class Question
{
public string Text { get; set; }
}
I have a web page with select
allowing the user to choose a Template
. Once they've selected one, it goes off and calls the above method to return that template's configuration.
Initially I'm creating my JavaScript view model with a list of these templates, like this.
function viewModel(templates) {
var self = this;
self.templates = ko.observableArray(templates);
}
// this is just a $.ajax call to another asmx service that gets me
// a JSON array of all templates
var templates = getTemplates();
var vm = ko.applyBindings(new viewModel(templates));
Then my markup uses this like so.
<select id="template" data-bind="foreach: templates">
<option data-bind="text: Name, value: Id"></option>
</select>
All working fine so far, I guess my question is what is the correct way to return a template's configuration and store this in the view model, and display on the page?
First attempt
I've added a property configuration
and a method getConfiguration
to the view model and am invoking this by having data-bind="change: getConfiguration
on the select
.
function viewModel(templates) {
var self = this;
self.templates = ko.observableArray(templates);
self.configuration = null;
self.getConfiguration = function () {
// calls the asmx web method, parses the returned JSON to an object
// and then...
self.configuration = $.parseJSON(data.d);
};
}
But I'm not having much luck, can anyone give me a friendly nudge in the right direction? Appreciate any and all help as always.
Second attempt
Based on mael's answer below, I've tried to set configuration
as an observable. Here's my markup (just trying to observe the template's name at the moment):
<div data-bind="if: configuration">
<strong data-bind="text: configuration.Name"></strong>
</div>
And the getConfiguration
method:
var config = $.parseJSON(data.d); // the ajax call to get the JSON
self.configuration = ko.observable(config);
I've also tried this with the mapping plugin:
self.configuration = ko.mapping.fromJS(config);
No luck though :s
Third attempt
I've decided to scrap the idea of storing the template list in my view model, and am just creating this list separately. The ko.applyBindings
is now called on the .change
event of my template list.
var viewModel = function (config) {
var self = this;
self.configuration = config;
}
$('#templates').unbind('change').on('change', function () {
var id = $(this).children('option:selected').val();
var config = getConfig(id); // calls my asmx method to get the config JSON
ko.applyBindings(new viewModel(config));
});
Having much more success with this (although not sure whether I needed to remove the template list from the view model) - but now getting the following error [You cannot apply bindings multiple times to the same element.].
Upvotes: 1
Views: 305
Reputation: 2254
If you're just getting a plain javascript object (which I think your template is), its properties do not become observable by knockout. You have to use knockout mapping plugin to make your template properties observable (see here: http://knockoutjs.com/documentation/plugins-mapping.html).
You could also do your own javascript "Template" object. Something like that:
function Template(jsonTemplate) {
this.id = ko.observable(jsonTemplate.id);
//etc.
}
And then building Templates object from your JSON objects.
Upvotes: 1