3

I have my Durandal routes configured as below.

var routes = [ 
....... More Routes Here.....
{
    url: 'login',
    moduleId: 'viewmodels/login',
    name: 'Log In',
    visible: true,
    caption: 'Log In'
}, {
    url: 'logout',
    moduleId: 'viewmodels/logout',
    name: 'Log Out',
    visible: false,
    caption: 'Log Out'
}, {
    url: 'register',
    moduleId: 'viewmodels/register',
    name: 'Register',
    visible: false,
    caption: 'Register'
}];

And everything is working as expected. I would like to be able to activate the Logout Route in my navigation when I log in and my log in button to become invisible. I have tried the following code and despite not throwing any errors it does not change the visibility of anything in the interface.

var isLoggedIn = ko.observable(false);
isLoggedIn.subscribe(function (newValue) {
    var routes = router.allRoutes();
    if (newValue == true) {
        for (var k = 0; k < routes.length; k++) {
            if (routes[k].url == 'logout') {
                routes[k].visible = true;
            }
            if (routes[k].url == 'login') {
                routes[k].visible = false;
            }
        }
     } else {
         for (var i = 0; i < routes.length; i++) {
             if (routes[i].url == 'logout') {
                 routes[i].visible = false;
              }          
              if (routes[i].url == 'login') {
                  routes[i].visible = true;
              }
         }
     }
});

I believe this doesn't work because visible is not an observable, isActive is a computed with no write capability so it does not work either. How can I dynamically change the visibility of my routes in the nav menu?

PlTaylor
  • 7,345
  • 11
  • 52
  • 94
  • Look at Joseph's answer here: http://stackoverflow.com/questions/16031226/durandal-js-change-navigation-options-per-area?answertab=active#tab-top. This should surely help you. – Yogesh May 14 '13 at 20:16

2 Answers2

0

Here is what I ended up doing.

//ajax call to log user in
.done(function (recievedData) {
    if (recievedData == true) {
        router.deactivate();
        return router.map(config.routesLoggedIn);
    } else {
        router.deactivate();
        return router.map(config.routes);
    }
}).done(function() {
    router.activate('frames');
    return router.navigateTo('#/frames');
});

Essentially created two routing profiles in my config object. One for logged in and one for not. There is one caveat. The router.deactivate() method is a very new method and is not in the NuGet package yet. I copied the code of the new router from the master branch of the GitHub repository for Durandal. There is some discussion on this new function on the Durandal User Group. Ultimately for security reasons I might feed the logged in routes from my server. But for the time being this should work just fine.

PlTaylor
  • 7,345
  • 11
  • 52
  • 94
0

Another approach is to make all routes available but use bound expressions to compose either the content or the login page into the container view specified by the route.

Instead of supplying a literal view name, bind the compose parameter to a ternary expression that chooses between the name of the login view and the name of the content view. The controlling expression would be an observable such as app.isAuthenticated() the value of which must be set when the user succeeds in logging in or out.

This approach is robust in the face of deep linking because it does away with the notion of a path through the application. Without explicit redirection logic, it will authenticate the user and then show the requested resource.

It can be extended to more than two possible states using a function instead of a ternary expression. This is handy when different UI must be delivered according to user permission.

Peter Wone
  • 17,965
  • 12
  • 82
  • 134