0
votes

On Durandal, I have a login page that's styled different from my other pages, so taking the advice I saw on some of the posts here, I've set up main.js to do a:

app.setRoot('viewmodels/login');

And on the login page, I provide the below method in login.js that resets the root:

loginRedirect: function() {
 app.setRoot('viewmodels/shell');
 }

The idea is that the user should go to the login page by default, and once logged in, I will invoke the method loginRedirect, which sets shell.html to be the root and thus reloads the content, and he should be able to navigate other pages from there.

Here's my login.html:

<div class="login">
  <div data-bind="compose:'header-nav-plain.html'"></div>
  <div class="container">
  <!-- Content here-->
  </div>
</div>

<div data-bind="compose:'viewmodels/footer'"></div> 
<a class="go-inner-pages" data-bind="click: loginRedirect" href="#">Test link to go to 'inner' pages</a>

And here's my shell.html, that is the doorway to all other pages:

<div>
  <div data-bind="compose:'viewmodels/header-nav'"></div>
  <div class="container">
    <div data-bind="compose:'viewmodels/site-nav'"></div>
    <div data-bind="router"></div>
  </div>
  <div data-bind="compose:'viewmodels/footer'"></div>
</div>

You can see that shell.html is slightly different in structure from login.html, in that it binds to a different header-nav.html, and also a site-nav.html. (They share the same footer.html.) So on the login page, when I click on the test link that calls the loginRedirect method, it sets the root of the app to be shell.html, which will load the default page based on the parameters passed to router.map, as defined in shell.js:

 activate: function(){
     //Initializing router
     router.map([
         { route: '', moduleId: 'viewmodels/dashboard', title: 'Dashboard', nav: true }     
     ])
     .buildNavigationModel();

     //More code

     return router.activate();

But, when I click on the test link and invoke loginRedirect, the new dashboard content is loaded, but the new header-nav and site-nav data binding didn't happen. I checked the inspector, and see that the structure has indeed changed to that of shell.html (as opposed to login.html), only data binding for header-nav and site-nav didn't happen. I.e. here's the new html after invoking loginRedirect:

<div>
  <div data-bind="compose:'viewmodels/header-nav'"></div><!--header nav content not bound-->
  <div class="container">
    <div data-bind="compose:'viewmodels/site-nav'"></div><!--site nav content not bound-->
    <div data-bind="router"><div class="durandal-wrapper" data-view="views/dashboard" data-active-view="true">

    <!-- Dashboard content successfully loaded -->

    </div><!--end data-bind="router"-->
  </div><!--end .container-->
  <div data-bind="compose:'viewmodels/footer'">
 <!--footer content loaded-->
 </div>

And from the Console (see below), one can see that while the shell and dashboard are bound, (even footer is bound a second time), header-nav and site-nav are not.

Screenshot of web inspector

Does anyone have any idea why this is happening and what I might be doing wrong? Thanks in advance for your attention, hope to hear from someone soon. Cheers.

1

1 Answers

0
votes

For view-only bindings, you would bind this way (we do the same as you, so I'm copying and pasting our code):

compose: {view: 'shellLeftFooter.html'}"

For views bound to viewModels, you bind this way:

compose: {model: 'viewmodels/navigation/shellNavigation'}

The default viewLocator will use the following convention:

  • If a view is specified with no model, then the view must be identified with the .html extension, as I have done in the former example, and it will not be bound to a viewModel;
  • If a model is specified with no view, as I have done in the latter example, then the model file is assumed to have a .js extension, and it is also assumed that a view exists in a folder named views under the app directory, with the same name as the model, but with an .html extension.

These aren't the only two conventions, but they are the ones germane to this discussion. To put the above in different words, make sure you have both a viewmodels and a views directory that are siblings of each other under the app directory. Make sure you give the viewModel and the view identical names, differing only in their extensions (.js for the former and .html for the latter).

I'm seeing all of your .html and .js files in the code you posted, so I'm sure what your intention is in each case (view only or model-view-viewModel). Also, your compose binding is not quite to standard.