Reputation: 8054
When using the following Durandal child router plugin configuration, I'm not getting the detached
and activate
events described in the Durandal lifecycle, while other events work.
It is a single page application, with the childRouter
controlling content of a div
container within it. Each childRouter
corresponds to a module and only one should be attached
at a time, while others should be detached
.
The application uses separate childRouter
instances for each module and I'm expecting the detached
and activate
events to be trigered each time navigation between two modules occurs (i.e. moduleOLD
should get detached
and moduleNEW
should get attached
).
Documentation says Durandal lifecycle events are triggered automatically:
Rows highlighted green will always execute when composing.
It doesn't work this way, which could be caused by:
It seems I have to detach something manually, or notify the router that is being replaced, to trigger detached
and activate
.
How to trigger the detached
and activate
events for childRouter
?
define([ 'durandal/app', 'plugins/router'], function(
app, router) {
var childRouter = router.createChildRouter();
childRouter.makeRelative({
moduleId : 'modules/moduleX/pages',
fromParent : true
});
childRouter.map([ {
route : [ '', 'grid' ],
moduleId : 'grid/index',
}, {
route : 'details/:id',
moduleId : 'details/index',
}, {
route : 'details/tabs/base',
moduleId : 'details/tabs/base',
} ]);
childRouter.buildNavigationModel();
childRouter.activate = function() {
console.log("activate");//DOESN'T WORK
};
childRouter.attached = function() {
console.log("attached");//WORKS
};
childRouter.compositionComplete = function() {
console.log("compositionComplete");//WORKS
};
childRouter.detached = function() {
console.log("detached");//DOESN'T WORK
};
return {
router : childRouter
};
});
Output (no errors):
compositionComplete (gets called here too, when a route is first visited)
attached
compositionComplete
Upvotes: 1
Views: 1582
Reputation:
In Durandal, activation lifecycle is specific to an activator. Each router, and child router, has one in activeItem, which also acts as an accessor to the currently activated module on that router.
Durandal ensures that the events from the lifecycle are properly called on each module when it changes or is about to change the active item on any of the currently active routers, and then when/if it binds the data to the module's view and attaches it to the DOM document.
To have the events triggered as intended, the methods with corresponding names should be declared on each module where such handler is required.
Activation takes place across all child routers, but happens in steps, starting from the root router. Thus, when picking a module for a new route, the root router will ask its currently active module if it canDeactivate, which will chain down to all of its active modules in the child routers. Then it will ask the new module if it canActivate. And if allowed by both, the activation will go through and the active item on the root router will change, triggerring the deactivate/activate methods on the modules, if present. If there is more to the route than the matched fragment and the activated module has a child router, the child routing on it will then be triggered as well.
When the same module is reused in the activation, the chain of events is still triggered, but it may happen so that the deactivate method on some of the modules activated in a child router may not trigger if that router doesn't receive a matched module from the new route. For example, it can happen if the child router isn't configured for a null route ('') and the navigation changes back to a parent route, say from products/item/15
back to products
, leaving the child router with no new match and no new module to switch to, meaning that whatever parent module was matched for products
will still have the old module for item 15
remain activated on its child router. To avoid such cases when reusing modules, one option is to always configure the null route ('') on child routers. If anything, match it to a module with a blank view, e.g. an empty div
.
Upvotes: 0