Knockout.js - linking view models with knockout-postbox
Knockout.js is a pretty cool MVVM framework but of course it's missing parts or good guidance on doing some crucial bits - such as my usual problem: linking different view models together.
Hopefully I don't have to explain why one might want to have many different view models (cough separation of concerns cough). The question is how to link them up nicely.
My initial (hack, quickfix) "solution" was to pass in the the View Model that the was depended on (i.e. View Model 2 wanted to know about a change in View Model 1) and then the dependent View Model 2 would subscribe to a particular property (or properties). Here I was at least following the publisher/subscriber model so there's less coupling, however View Model 2 is still directly dependent on View Model 1.
The usual coupling questions arise (I break everything if I change View Model 1 a lot, what if I want different ways of changing the same property - does View Model 2 need to have every reference?).
As a I said, the original hack was just that - a hack. So as soon as I hit the second case of dependencies I followed my rule of "as soon as you do something more than once, find a better way of doing it" (the trick is always being aware of what you're doing more than once) - so I hunted around and found this (so far) lovely Knockout plugin: knockout-postbox
It works on, more-or-less, the same publisher/subscriber principle I was using, but in a far more decoupled and cleaner way.
It uses the concept of 'topics', where certain properties will publishTo() a topic whenever they change. In view models that need to know about these changes, properties should subscribeTo() that topic to receive updates.
Example:
function PublisherViewModel() {
this.mode = ko.observable('something').publishOn('viewmode');
this.viewModeSelection = function() { this.mode('newmode'); }
}
function SubscribeViewModel() {
this.viewMode = ko.observable('something').subscribeTo('viewmode');
}
So, whenever mode chnages in PublisherViewModel the SubscribeViewModel() will receive changes on it's viewMode property.
If you've got code that is not Knockout then you can use the postbox API to subscribe to topic updates (check out the code on https://github.com/rniemeyer/knockout-postbox for an example).
Of course, with the above model you'll have duplication of the same property on many view models. I feel there must be a better way of handling this but I've not had to do it enough times (yet) to warrant finding something better.