We are refactoring our client code and implementing viewmodels. I'd like to keep our viewmodels as dumb as possible, having them be solely data representations.
We'll use a view controller and pub/sub to get fresh data for the vm as required, and just push the data into the viewmodel in a one-way data hierarchy model akin to the way components communicate in Vue.
For flat viewmodel properties this approach works fine, using a 'Props' function, but for a case of nested observables like address, I lose the observable (of course).
var model = function() {
var self = this;
self.name = ko.observable();
self.occupation= ko.observable();
self.address = ko.observable({
street: ko.observable('Streetname'),
zip: ko.observable('Zipcode')
});
self.doUpdate = function() {
self.props({name: 'Tom', address: {street:'NewStreet'}});
};
self.props = function(data) {
var viewmodel = self;
for (p in data) {
if (self[p]) {
self[p](data[p]);
}
}
};
}
ko.applyBindings(new model());
I can't pass in
self.props({name: 'Tom', address: {street:ko.observable('NewStreet')}});
because I have to assume we'll just be getting a data structure from a service or other module, and it's the viewmodel's job to manage what are observables or not.
The alternative I thought of was just using the ko mapping functionality, but that requires a little more intelligence in my Props function, where I would do something like
if(self['mapping_' + p]){
//If self.mapping_address() exists, use that to
//create mapped observables...
}else if(self[p]){}...
I'd be comfortable with this, but it seems a little kludgey. Is there a better way to accomplish maintaining nested observables when passing in hierarchical data from a service or controller?
I take it you have your own ajax(get/post) implementation wrapped in a little library, what we do is we have our own xhrObject(jqXHR) that returns a promise, before we resolve the deferred of that promise we can choose if we change the properties to observables or not so that the viewmodel implementation doesn't have to deal with converting each api call.
Here's a little thingy to get you on your way, hope it helps