DOM for my Durandal app is structured as below:
//shell.html
<div id="applicationContentWrapper" >
<!-- ko compose: {model: 'viewmodels/header', activate:true} --> <!-- /ko -->
<div data-bind="router:{}"></div>
</div>
Here's a snippet of my router configuration
router.map([
{ route: '', moduleId: 'viewmodels/dashboard', name: 'dashboard'},
{ route: 'form', moduleId: 'viewmodels/form', name: 'form'},
{ route: 'login', moduleId: 'viewmodels/login', name: 'login'}
]);
As you can see my login view gets inserted into the <div data-bind="router:{}"></div>
which is the expected behaviour. But if I am on the login view I need to hide the header view which I have managed to do by subscribing to the router configuration in the header viewmodel:
router.activeInstruction.subscribe(function (val) {
val.config.name === "login" ? showHeader(false) : showHeader(true);
});
But this feels a little messy and the DOM for the header view is still in the page, what I really want to do is if I am in the in the login view I just want the DOM for the login view to be there as if I am in separate page with only the login view. But so far I have not found a clean way to do it.
A few things:
with
or if
-binding. They hide whatever's inside if the condition is falsy.I can understand your reasoning for wanting a whole different 'layout' without the rest of the DOM for your login view. But this goes against the whole idea of a single-page application. It is also unnecessary. A bit of smart css and data-binding (visible, if, with) will give you the same results, often providing a better user experience than a full page reload would do. If you insist on breaking the SPA though, place a router one level lower: e.g. the main router only knows a login route and an internal route. The internal route has another router which holds all the other pages. This way you can move the common HTML from your shell view to the internal view.