I have a multi-page application with a navigation panel that is used across all pages. Each page has its own view model, the panel view model is the same. I could remember to always bind both models but I was hoping there would be a more universal solution. Some way to bind my one-page model to the whole document, and yet have an island of DOM elements automatically bound to a different model.
Here’s what I knew would work, but I didn’t like:
-
<script src="page-1.js"></script>
-
<div id="navigation-panel" data-bind="with: navModel">…</div>
-
<div id="page1" data-bind="with: page1Model">…</div>
-
The trouble is that I have to remember to bind navModel in page-1.js
and all page-x scripts.
-
var model = {
-
‘navModel’ : new NavModel,
-
‘page1Model’ : new Page1Model
-
};
-
ko.applyBindings(model);
-
I didn’t want page-1.js
to care about elements that are on every page.
Solution 1: Component
-
<script src="navigation.js"></script>
-
<script src="page-1.js"></script>
-
<script type="text/html" id="template-navigation">
-
<div id="navigation-panel">…</div>
-
</script>
-
<div data-bind="component: ‘navigation’"></div>
-
<div id="page1">…</div>
navigation.js:
-
ko.components.register(‘navigation’, {
-
template: { element: ‘template-navigation’ },
-
viewModel: NavModel
-
});
page-1.js:
-
ko.applyBindings(new Page1Model);
This worked well but I didn’t like the extra markup. Also, I actually have several islands and I didn’t like having to define a component for each.
Solution 2: Custom binding handler
-
<script src="navigation.js"></script>
-
<script src="page-1.js"></script>
-
<div id="navigation-panel" data-bind="viewModel: navModel">…</div>
-
<div id="page1">…</div>
navigation.js:
-
var navModel = new NavModel;
-
ko.bindingHandlers.viewModel = {
-
init: function(element, valueAccessor) {
-
ko.applyBindingsToDescendants(valueAccessor(), element);
-
return { controlsDescendantBindings: true };
-
}
-
};
page-1.js:
-
ko.applyBindings(new Page1Model);
Nice and smooth. One handler takes care of all islands, all I have to do is to define a global variable for each view model.
Tags: Knockout 3.3.0