Durandal Child Routing Issue - Back Button

834 views
Skip to first unread message

Abrahm Coffman

unread,
Jan 21, 2014, 9:31:55 PM1/21/14
to duran...@googlegroups.com
Hi All,

I have a page where I need to load child routes via a child composition rather than via the original parent composition.  However when I do this it breaks the back button.  I think the back button still maintains the child router, which it shouldn't.  Here's a contrived example:

// shell.js

define(['router'], function Shell(router) {
  return {
    router: router,
    activate: function() {
      return router.map([
        { route: ['', 'products'], moduleId: 'product' },
        { route: 'products/*details',  moduleId: 'product',   hash: '#products' }
      ]).mapUnknownRoutes('product', 'products')
        .activate();
    }
  };
});

// shell.html
<div data-bind="router: { transition:'entrance', cacheViews:false }"></div>


// product.js

define(['router'], function Product(router) {

  var childRouter = router.createChildRouter().makeRelative({
      fromParent: true
  }).map([
    { route: ':id', moduleId: 'productDetail', title: 'Detail', type: 'intro', nav: false }
  ]);

  return {
    router: childRouter,
    activate: function() {}
  };
});

// product.html
<div data-bind="router: { transition:'entrance', cacheViews:false }"></div>


// productDetail.js

define([], function ProductDetail() {
  return {
    activate: function(id) {
        // request some server data using the id
    }
  };
});


When I visit the child route (#product/123) and then click the back button, I get a hash something like this:

#123

When it should be

#product

Any ideas what might be happening?

Abrahm Coffman

unread,
Jan 23, 2014, 8:16:58 PM1/23/14
to duran...@googlegroups.com
I found the root cause of the problem.  It's the following line in router.loadUrl

if (currentInstruction) {
    history.navigate(currentInstruction.fragment, { trigger:false, replace:true });
}

Any ideas why this line is necessary?  Commenting it out fixes all my problems.

Abrahm Coffman

unread,
Jan 23, 2014, 8:38:04 PM1/23/14
to duran...@googlegroups.com
I propose the following solution:

            if (currentInstruction && !router.relativeToParentRouter) {
                history.navigate(currentInstruction.fragment, { trigger:false, replace:true });
            }

Does anybody see any issues with that?

Abrahm Coffman

unread,
Jan 24, 2014, 3:28:09 PM1/24/14
to duran...@googlegroups.com
Ok last post on this issue.  It looks like if you setup a default route in the child router, even if it just maps to a dummy module, it fixes the problem.  So I'm gonna role with that.  I'm not sure if this is clearly documented, or even if this is what should be required, but I'll go with it.

  var childRouter = router.createChildRouter().makeRelative({
      fromParent: true
  }).map([
    { route: '',     moduleId: 'default',          title: 'Detail', type: 'intro', nav: false },
    { route: ':id', moduleId: 'productDetail', title: 'Detail', type: 'intro', nav: false }
  ]);

Jonas

unread,
Jan 27, 2014, 6:49:22 AM1/27/14
to duran...@googlegroups.com
Hi Abrahm.

I faced the same issue. There is a problem in the case of child router. The default behaviour is to set the last matching route when no one has matched and to update the url to reflect this change. The problem is that it doesn't take into account the router's parents and just set the hash to the current instruction fragment. What I have done is to modify the code to construct the right hash based on the rootRouter's active instruction fragment (removing any unexpected route).

Of course this is the default behaviour when no route matches, so you can make so this never happen, as you are saying in your last message. But you only define an empty route, so you will still have problems with unexpected pattern, such that "#product/TOTO". So you should rather use 'mapUnknownRoutes' that will add a route with the splat pattern '*catchall' catching any route not catched by a previous pattern. (As this just adds a route with a catch all pattern, it is important to call 'mapUnknownRoutes' after you mapped your routes, otherwise it will hide them).
Reply all
Reply to author
Forward
0 new messages