Durandal third-level subrouting - durandal

I'm trying to make child router of a child router in Durandal.js, but getting random dumb errors (for example 404 etc.). Is it Durandal's issue (I mean if it has not third-level subrouting support) or it's maybe my code problem?
Thanks
Anyways, I'm going to include my code here:
returning shell
return {
router: router,
activate: function () {
return router.map([
{
route: ['', 'Main'],
moduleId: 'Main/index',
nav: false
},
{
route: 'Main*details',
moduleId: 'Main/index',
hash: '#/Main/',
title: 'Main',
nav: false
}
]).buildNavigationModel()
.activate();
}
};
returning 2nd level child
var mainRouter = router.createChildRouter()
.makeRelative({
moduleId: 'Main',
fromParent: true
}).map([
{
route: ['', 'Dashboard'],
moduleId: 'Dashboard/index',
nav: false
},
{
route: 'Dashboard*details',
moduleId: 'Dashboard/index',
hash: '#/Main/Dashboard',
title: 'Dashboard',
nav: true
}
]).buildNavigationModel();
return {
router: mainRouter
}
returning 3rd level child
var dashboardRouter = router.createChildRouter()
.makeRelative({
moduleId:'Dashboard',
fromParent: true
}).map([
{
route: ['', 'Product'],
moduleId: 'Product/index',
hash: '#/Main/Dashboard/Product',
title: 'Product',
nav: true
}
]).buildNavigationModel();
return {
router: dashboardRouter
}

I believe it's currently a bug in child routers that are at the 3rd level or below. We have this tracked as an issue and are working on a solution. I apologize for the inconvenience.

hah... This is quite simple:
(var dashboardRouter = router.createChildRouter()
.makeRelative({
moduleId:'Dashboard',
fromParent: true
}).map([
{
route: ['', 'Product'],
moduleId: 'Product/index',
hash: '#/Main/Dashboard/Product',
title: 'Product',
nav: true
}
]).buildNavigationModel();
return {
router: dashboardRouter
}).makeRelative({
moduleId: 'Main',
fromParent: true
}).map([
{
route: ['', 'Dashboard'],
moduleId: 'Dashboard/index',
nav: false
},
{
route: 'Dashboard*details',
moduleId: 'Dashboard/index',
hash: '#/Main/Dashboard',
title: 'დეშბორდი',
tab: "dashboard",
nav: true
}
]).buildNavigationModel();
return {
router: mainRouter
}

Related

Using the Aurelia router, how do I define two routes to the same view?

I have a sub-router. Let's say it's for fancy fruits. In that sub-router, I want to define routes to specific fruits that will show up in the navigation using RouteConfig nav: true as such:
config.map([
{ route: [":fruit"], name: "AppleFruit", moduleId: PLATFORM.moduleName("./fruity-fruit-fruit"), nav: true, title: "Apples are yum!", layoutModel: { fruit: "Apple" } },
{ route: [":fruit"], name: "LemonFruit", moduleId: PLATFORM.moduleName("./fruity-fruit-fruit"), nav: true, title: "Lemons are for booze!!", layoutModel: { fruit: "Lemon" } }
]);
Specifically, I'm wanting to do it this way because there are navigation elements on the page that rely on other routes in this sub-router, and I would like these to appear in the navigation with the others. My thought was that the layoutModel would get passed into the activate params in fruity-fruit-fruit, but it just blows up before making it to that point.
Is this possible, or what am I doing wrong?
As often happens, I have found the answer. My problem was that I was using layoutModel instead of just specifying the href. It should have been:
config.map([
{ route: [":fruit"], name: "AppleFruit", moduleId: PLATFORM.moduleName("./fruity-fruit-fruit"), nav: true, title: "Apples are yum!", href: "/fruits/Apple" },
{ route: [":fruit"], name: "LemonFruit", moduleId: PLATFORM.moduleName("./fruity-fruit-fruit"), nav: true, title: "Lemons are for booze!!", href: "/fruits/Lemon" }
]);

Aurelia Child Router redirect to specific route

I have a main App router and multiple child routers. I'd like to have the option of specifying the child route to open when navigating from the parent route.
Parent Router:
configureRouter(config, router) {
this.router = router;
config.map([
{ route: ['','home'], name: 'home', moduleId: 'home/home' },
{ route: 'students/:id?', name: 'students', moduleId: 'students/students' },
{ route: 'staff', name: 'staff', moduleId: 'staff/staff' }
]);
}
Child Router for Students:
export class Students {
configureRouter(config, router) {
config.map([
{ route: ['', 'home'], name: 'student-home', moduleId: 'students/students-home' },
{ route: 'list', name: 'student-list', moduleId: 'students/student-list' },
{ route: 'profile/:id', name: 'student-profile', moduleId: 'students/profile/overview' },
{ route: 'lockers', name: 'student-lockers', moduleId: 'students/lockers/home' }
]);
this.router = router;
}
activate(params) {
if (params.id) {
console.log("Going straight to a student record for: ", params);
this.router.navigateToRoute('student-profile', {id: params.id});
}
}
}
The above scenario (using navigateToRoute() within activate) doesn't work, nor am I sure it's the best way. How can I have the option to navigate straight from the main app router to the student-profile screen if I include an id param?
I gave up on using named routes with child routers. If someone else understands them better than me, I'd be curious. However, I have found it works perfectly to just use the URL routing from any part of the app.
this.router.navigate('#/students/profile/' + record.id);
You don't need to use active in your child route. Aurelia router will go automatically to your child route.
export class Students {
configureRouter(config, router) {
config.map([
{ route: ['', 'home'], name: 'student-home', moduleId: 'students/students-home' },
{ route: 'list', name: 'student-list', moduleId: 'students/student-list' },
{ route: 'profile/:id', name: 'student-profile', moduleId: 'students/profile/overview' },
{ route: 'lockers', name: 'student-lockers', moduleId: 'students/lockers/home' }
]);
this.router = router;
}
}
Remove active and in your module "students/profile/overview"
call active(params) to get student from api or what ever you want you can do here with provied params.

Aurelia: Child Router Navigation: Route not found

Below are my views:
1. app - standard
2. home - Has a list of items on left, on selection of any, will display some content on the right side in router-view (contract-view to be loaded).
3. contract-view
app.ts: route Config:
configureRouter(config: RouterConfiguration, router: Router) {
config.title = 'Contracts Portal';
config.map([
{ route: ['', 'home'], name: 'home', moduleId: 'home', nav: true, title: 'Home' },
{ route: 'resources', name: 'resources', moduleId: 'resources', nav: true, title: 'Resources' },
{ route: 'tools', name: 'tools', moduleId: 'tools', nav: true, title: 'Tools' }
]);
this.router = router;
}
Home.ts Router Config:
configureRouter(config: RouterConfiguration, router: Router) {
config.title = "test";
config.map([
{ route: ['', 'contract-view/:id'], name: 'contract-view', moduleId: 'contract-view', nav: true, title: 'Test' }
]);
this.router = router;
}
on selection of a item in home page list, I am trying to navigate as below to load content in the right pane's router-view, in home.ts:
this.router.navigateToRoute("contract-view", { id: 4090 });
However it throws the error: Route not found: /contract-view/4090
At this point, it's still home page and default route, hence the url reads: http://localhost:9000/#/
and so it fails.
But, if I manually change the url to http://localhost:9000/#/home and then select a list item, navigation to contract-view works.
What I am I missing here?
I am looking for absolute path navigation. Tried navigating to home/contract-view but fails with error:
A route with name 'home/contract-view' could not be found. Check that name: home/contract-view was specified in the route's config.
The default route of Home.ts has a parameter:
config.map([
{ route: ['', 'contract-view/:id'], name: 'contract-view', moduleId: 'contract-view', nav: true, title: 'Test' }
]);
This might be a problem because the parameter :id is not referenced in the first name. So, I suggest you change the route as follow:
config.map([
//create another route with no parameters,
//this route will represent an empty selection of contract
{ route: [ '', 'contract-view' ], name: 'contract-view-empty', moduleId: 'contract-view-empty', Title: 'Select a Contract' }
{ route: 'contract-view/:id', name: 'contract-view', moduleId: 'contract-view', nav: true, title: 'Test' }
]);
Then, to generate a navigation link you can use route-href attr. Like this:
<a route-href="route: contract-view; params.bind: { id: 4090 }">Navigate</a>
Hope it helps!
It is an issue with Aurelia Router framework. Discussion and workaround here:
https://github.com/aurelia/skeleton-navigation/issues/230

durandal 3rd level child router

Once I declare 3rd level router, I am facing problem in navigation between modules defined in 2nd level router.
The issue is: when I navigate in between different modules at 2nd level router, activate is fired but attached is not fired for the module.
Code snippet for routers is as follow:
//1st level router
landing.router = router.map([
{ route: 'resourcebrowser*splat', title: 'Resource', moduleId: 'viewmodels/resourcebrowser', nav: true },
]).buildNavigationModel();
//2nd level router
var childRouter = parentView.router = landing.router.createChildRouter()
.makeRelative({
moduleId: 'viewmodels/tab/',
fromParent: true
}).map([
{ route: ':id/details', moduleId: 'details', title: 'Details', type: 'intro', nav: true },
{ route: ':id/docs*splat', moduleId: 'documents', title: 'Documents', type: 'intro', nav: true }
]).buildNavigationModel();
//3rd level router
var childRouter = parentView.router.createChildRouter()
.makeRelative({
moduleId: 'viewmodels/viewer/',
route: ':id/docs/'
})
.map([
{ route: 'documentviewer/:docid', moduleId: 'documentviewer', title: 'Viewer', type: 'intro', nav: true }
]).buildNavigationModel();
Kindly let me know where am I going wrong.
Check the documentation for canReuseForRoute : http://durandaljs.com/documentation/Using-The-Router.html
If you define the canReuseForRoute function and return false, I believe you will find that 2nd level router viewmodel is recreated completely as you intend.

Define the starting module in durandal 2.0 and navigate to it

It seems to me... that this way the initial route is defined via:
{ route: '', moduleId: 'viewmodels/customers', title: 'customers', nav: true },
When the application is loaded with the route '' which must be oddly set to empty then this route is loaded initially.
When I navigate now to mysite/#/customers nothing is loaded.
How can I give my route a starting module which I can use to navigate to it?
In the old router I used startModule but I can not find it in durandal 2.0.
You probably need to setup a second route with the same moduleId. Here's a live example for child routes that uses this http://dfiddle.github.io/dFiddle-2.0/#hello and http://dfiddle.github.io/dFiddle-2.0
define(['plugins/router', 'durandal/system', 'global', 'knockout'], function( router, system, global, ko ) {
var childRouter = router.createChildRouter()
.makeRelative({
moduleId: 'hello',
route: 'hello'
}).map([
{route: '', moduleId: 'default/index', title: 'Hello World', type: 'intro'},
{route: 'default', moduleId: 'default/index', title: 'Hello World', type: 'intro', nav: true},
{route: 'dFiddle', moduleId: 'dFiddle/index', title: 'Hello World', type: 'fiddle', nav: true}
]).buildNavigationModel();
// .on is mixed in an not meant to be chainable
childRouter.on('router:navigation:complete').then(global.createSampleLink);
return {
global: global,
router: childRouter,
getItemsByCategoryId: function( categoryId ) {
return ko.utils.arrayFilter(childRouter.navigationModel(), function( route ) {
return route.type === categoryId;
});
},
binding: function() {
system.log('Lifecycle : binding : hello/index');
return { cacheViews: false }; //cancels view caching for this module, allowing the triggering of the detached callback
}
};
});
This specific setup that has child routes on all top routes use router.guardRoute in shell.js to handle the empty root case. There's an open ticket https://github.com/BlueSpire/Durandal/issues/240 that discusses better handling of these kind of edge cases.
define(['plugins/router'], function (router) {
// Redirecting from / to first route
router.guardRoute = function(routeInfo, params, instance){
if (params.fragment === ''){
return routeInfo.router.routes[0].hash;
}
return true;
};
return {
router: router,
activate: function () {
router.map([
{ route: '', moduleId: 'hello/index', title: 'Hello World' },
{ route: 'hello*details', hash: '#hello', moduleId: 'hello/index', title: 'Hello World', nav: true },
...
]).buildNavigationModel();
return router.activate();
}
};
});
You can declare your routes like this:
routes = [
{ route: ['welcome', ''], title: 'Welcome', moduleId: 'welcome', nav: true },
{ route: 'Visits', title: 'Visits', moduleId: 'Visits', nav: true },
{ route: 'VisitAddEdit', title: 'Add New Vsit', moduleId: 'VisitAddEdit', nav: true }
];
Notice how the welcome route is declared as an array (['welcome', '']) that includes an empty string in addition to a name.
This may not be the best long-term solution, but my fix was to pass in a startUrl in the options object of router.activate() and then change one line of history.js (line 163, the end of the activate function):
return history.loadUrl(options.startUrl);
I call it like this after I set up the router mapping and buildNavigationModel:
router.activate({startUrl: 'hello'});
Hope that helps as a quick fix.
EDIT
To get the URL to update as well, I changed it to history.navigate(options.startUrl) instead of loadUrl.