single-page-applicationdurandal-2.0durandal-navigation

Durandal 2 upgrade redirect issue


Hello and thanks for taking a look at my issue.

I have been migrating my SPA application to use the Durandal 2.0 library, following the sage advice from my oft savior, John Papa. And now that I have completed the upgrade process, I find a strange behavior (or a lack of behavior) when I try to navigate using my menu buttons. Specifically what isn't happening is the browser doesn't redirect to the new page. The interesting thing is that the browser address bar is populated properly and if I simply click in the address bar and press enter (hard reload), I am redirected as expected.

I've looked around and this is not caused due to any security check/redirect which I have seen other discussing elsewhere. Durandal code is unmodified.

js on pages can be quite trivial:

define([], function () {
    console.log("welcome loaded");
    var vm = {  
        title: 'Welcome'
    };

    return vm;
});

So my guess is its something in my configuration of durandal.

main.js:

    require.config({
    paths: {
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions',
        'knockout': '../Scripts/knockout-2.3.0',
        'bootstrap': '../Scripts/bootstrap',
        'jquery': '../Scripts/jquery-1.9.1'
    },
    shim: {
        'bootstrap': {
            deps: ['jquery'],
            exports: 'jQuery'
        }
    }
});

define('jquery', function () { return jQuery; });
define('knockout', ko);

define(['durandal/system', 'durandal/app', 'durandal/viewLocator'],
    function (system, app, viewLocator) {

    // Enable debug message to show in the console 
        system.debug(true);

    app.configurePlugins({
        router: true,
        dialog: true,
        widget: true
    });

    app.start().then(function () {
        toastr.options.positionClass = 'toast-bottom-right';
        toastr.options.backgroundpositionClass = 'toast-bottom-right';

        // When finding a viewmodel module, replace the viewmodel string 
        // with view to find it partner view.
        viewLocator.useConvention();

        // Adapt to touch devices
        // app.adaptToDevice();
        //Show the app by setting the root view model for our application.
        app.setRoot('viewmodels/shell', 'entrance');
    });
});

shell.js:

define(['../../Scripts/durandal/plugins/router', 'viewmodels/config', 'services/datacontext'], function (router, config, datacontext) {

    function addSession(item) {
        router.navigate(item.hash);
    }

    function boot() {
        //    $(".page-splash-message").text("Configuring routes...");
        router.makeRelative({ moduleId: 'viewmodels' });
        router.map(config.routes);
        router.buildNavigationModel();
        $(".page-splash-message").text("Let's make traxx..!");

        return router.activate();
    }

    function failedInitialization(error) {
        var msg = 'App initialization failed: ' + error.message;
    }

    return {
        addSession: addSession,
        adminRoutes: adminRoutes,
        profileRoutes: profileRoutes,
        visitorRoutes: visitorRoutes,
        router: router,

        activate: function () {
            datacontext.primeEditData().then(boot).fail(failedInitialization);
        }
    };
});

routes in config.js

define(['../../Scripts/durandal/plugins/router'], function (router) {
        toastr.options.timeOut = 4000;
        toastr.options.positionClass = 'toast-bottom-right';
        var startModule = 'Welcome';
        var serviceName = 'api/Zepher';
        var imageSettings = {
            imageBasePath: '../content/images/photos/',
            unknownPersonImageSource: 'unknown_person.jpg'
        };

    var routes = [
        { route: '', moduleId: 'home/welcome', title: 'Welcome', nav: false, },
        { route: 'Welcome', moduleId: 'home/welcome', title: 'Welcome', nav: false, },
        { route: 'NotFound', moduleId: 'home/notFound', title: 'Not Found', nav: false, },
        { route: 'Roadmap', moduleId: 'home/roadmap', title: 'Roadmap', nav: false, },
        { route: 'Register', moduleId: 'account/register', title: 'Register', nav: true, caption: '<i class="fa fa-user"></i> Register' },
        { route: 'RegisterAccounts', moduleId: 'account/registerAccounts', title: 'Register Accounts', nav: false, caption: '<i class="fa fa-key"></i> Register Accounts', },

    ];
        return {
        debugEnabled: ko.observable(true),
        imageSettings: imageSettings,
        servicetitle: serviceName,
        startModule: startModule,
        router: router,
        routes: routes,
        activate: function () {
            console.log("config activate called");
            router.makeRelative({moduleId: 'viewmodels'});
             router.map(routes);
             router.buildNavigationModel(); 

            //sets up conventional mapping for 
            //unrecognized routes
             router.mapUnknownRoutes('home/nontFound', 'not-found'); 

            //activates the router
             return router.activate(); 
            // no longer needs a start module
        }
    };
});

Solution

  • found what I was missing in my upgrade, so I thought I'd share what I've learned.

    Seems I forgot to update my Shell.html file.

    From this:

    <div>
        <header>
            <!--ko compose: {view: 'shared/nav', afterCompose: router.afterLogging, transition: 'entrance' } --><!--/ko-->
        </header>
         <section id="content" class="main">
             <!--ko compose: {model: router.activeItem, afterCompose: router.afterCompose, transition: 'entrance', cacheViews: true } --><!--/ko-->
        </section>
        <footer>
            <!--ko compose: {view: 'shared/footer'} --><!--/ko-->
        </footer>
    </div>
    

    to This:

    <div>
        <header>
            <!--ko compose: {view: 'shared/nav', afterCompose: router.afterLogging, transition: 'entrance' } --><!--/ko-->
        </header>
         <section id="content" class="main container-fluid page-host" data-bind="router: { transition: 'entrance', cacheViews: true }">
        </section>
        <footer>
            <!--ko compose: {view: 'shared/footer'} --><!--/ko-->
        </footer>
    </div>