durandaldurandal-navigation

Durandal Child router re-activate all level up to root


We are developping an application with durandaljs and we seems to have issues with child routers or at least, something we don't understand or can't figure out. Let's start with an exemple.

Route => /part1/:id/part2/:id2/part3

The problem, the main.js activate method is called on every level of routing while navigating :

= Root (activate called)
== Part1 (activate called)
=== Part 2 (activate called)
==== Part 3 (activate called (normal since this is the initiator of everything else since that's where we have navigating to, no more child router declare here as it live in the child router declare in Part2))

We found that behavior kind of weird and wonder if this is the normal behavior or if we do something really wrong here with child routers. Why every sub level need to re-run their activation method? IHMO, there's only the current model where we are navigating to that should trigger his activate method and any other sub page shouldn't fire this event.

We are using the latest DurandalJS available which is 2.1.0 and we are building the application with Typescript, although I don't think it change something here.


Solution

  • This is the normal behavior. The activate function is propagated throughout the hierarchy whenever a child is activated. This does not match the deactivate behavior. Deactivating a child while the parent is still instantiated does not invoke the deactivate on the parent.

    The best way to handle this is by switching on the arguments of the activator callback, since the activation arguments are passed to each activator callback. Thus, for part 1, you might have

    activate(id1, id2) {
        if (id1 === null && id2 === null) {
            // logic
        }
    }
    

    This misses the edge case where you navigate to /part1//part2, so if this is something concerned about, you can make a more robust check using regular expressions on the root router.

    import router = require('plugins/router');
    activate(id1, id2) {
        var route = /^part1\/?$/;
        if (route.test(router.activeInstruction)) {
            // logic
        }
    }