Recently, I worked with several people on questions related to binding multiple view models in a single page. One common approach is to bind a view model to a particular root element using a call like
ko.applyBindings(vm, containerNode);. However, a limitation with this approach is that when binding multiple view models, none of the container elements can overlap. This means that you could not bind one view model nested inside of another.
One way to address this issue is to create a top level view model that contains your “sub” view models and then call
ko.applyBindings on the entire page with the overall view model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Now in the view, you can use the
with binding along with
$root to bind a nested view model:
1 2 3 4 5 6 7
This technique is nice, because you only have to make a single
ko.applyBindings call and you can use
$parents to access data at any time from another view model. However, based on a desire to maintain modular code and to control how and when elements are bound, it is often not convenient or practical to build a top level view model.
With Knockout 2.0, there is a simple alternative that can provide for greater flexibility. Bindings are now able to return a flag called
controlsDescendantBindings in their
init function to indicate that the current binding loop should not try to bind this element’s children. This flag is used by the
template and control-flow bindings (wrappers to the
template binding), as they will handle binding their own children with an appropriate data context.
For our scenario, we can take advantage of this flag and simply tell Knockout to leave a certain section alone by using a simple custom binding:
1 2 3 4 5
Now, we can bind our “shell” model to the entire page and bind our “profile” model to the specific container:
1 2 3 4 5 6 7 8 9 10 11 12 13
In our view, we can now use the simple
stopBinding custom binding around our inner container element:
1 2 3 4 5 6 7 8 9 10
Adding the extra div to hold our
stopBinding binding may not cause our app any problems, but if it does then in KO 2.1 we can now create containerless custom bindings by adding our binding to
1 2 3 4 5 6 7
and finally we can clean up our view to look like:
1 2 3 4 5 6 7 8 9
With this simple binding, we can now compose pages with multiple view models without the worry of conflicting/overlapping bindings.
Here is a live sample: