How to dynamically build navigation menu from routes linking to parent/child views/controllers
Asked Answered
X

1

0

This question is a follow-up question for my original question Linking directly to both parent+child views/controllers from the main navigation menu

The accepted answer is great, but later when I added a 2nd "childRoute" dynamically, I noticed a problem. In order to build my navigation dynamically I had to add the multiple routes with the same "route" attribute. (see app.js in the example code below). The only difference were the "title" and "settings" attributes.

configureRouter(config, router){
    config.title = 'Aurelia';
    config.map([
        { route: 'shared-parent', moduleId: './shared-parent', settings: { childRoute: 'child-a' }, nav: true, title: 'Shared Parent - child-a' },
        { route: 'shared-parent', moduleId: './shared-parent', settings: { childRoute: 'child-b' }, nav: true, title: 'Shared Parent - child-b' },
        ...
    ]);

    this.router = router;
  }

The settings attribute I used in the view for doing this:

<a if.bind="row.settings.childRoute" href.bind="row.href + '/' + row.settings.childRoute">${row.title}</a>

I know it's not pretty but it does navigate to the right child route. The problem is that it's always the last of the 2 routes with duplicate "route" attributes that is marked as active.

The reason why I added the settings: {childRoute: 'child-a/b' } instead of giving them distinct "route" attributes like route: 'shared-parent/child-a' and route: 'shared-parent/child-b' was that the url would actually then match shared-parent/child-a/child-a and shared-parent/child-b/child-b since we're first linking to the shared-parent.

This live runnable gist should clearly display the problem (child-a route never activating): https://gist.run/?id=95469a9cb3a762d79da31e0b64248036

Ps. If you have a better idea of what to call the title of this question please feel free to edit it.

Xena answered 16/3, 2017 at 11:3 Comment(0)
E
1

So I took a stab at your problem using the EventAggregator in the Activate lifecycle hook in the child view models.

https://gist.run/?id=bfb5df5e39ac0bb73e9e1cae2d2496e2

in the child view models, I just published an event stating the child route was updated:

activate(params, routeConfig, navigationInstruction) {
  let payload = navigationInstruction.parentInstruction.config.title;

  payload = payload.substring(0, payload.length - 7);

  this.aggregator.publish("child route updated", payload + "child-a");

}

In the app.js file, I updated the route titles, and added an activeChild property. Next, update the activeChild property when the event is captured:

constructor(aggregator) { 

  this.aggregator = aggregator; 



  this.aggregator.subscribe("child route updated", payload => { 

    this.activeChildRoute = payload;

    console.log(this.activeChildRoute);

  });

}

Finally, I updated the class expression on you list item to update based on that active child Flag:

    <li repeat.for="row of router.navigation" 
        class="${row.title === activeChildRoute ? 'active' : ''}">
Epistrophe answered 21/3, 2017 at 15:43 Comment(1)
Hi James. This is actually a brilliant solution. I just added activationStrategy: 'replace', to each route in order for it to not "persist" the parent state between child routes. Thanks alot.Xena

© 2022 - 2024 — McMap. All rights reserved.