skip to Main Content

Twitter bootstrap has a dropdown menu option; where a menu has have multiple layers. See: http://getbootstrap.com/javascript/#dropdowns

How can I use Aurelia.js’s routers to recreate this? Routers normally provide 1 level. I need 2 levels.

3

Answers


  1. Chosen as BEST ANSWER

    Credit for this goes to: https://github.com/adarshpastakia.

    I "borrowed" most of this person's code to answer this question. You can find it at: https://gist.github.com/adarshpastakia/5d8462b5bc8d958d5cb3

    Here are steps to answer the question above:
    (1) In the router, add a "settings" property. It can be whatever you want. Here is an example:
    settings:{ subMenu:[ {href:'#/sub1', title:'Submenu 1'}, {href:'zoldello.wordpress.com', title:'Submenu 2'}, {href:'#/sub3', title:'Submenu 3'} ] }

    Note: (a)It must be called "settings" (b) Aurelia currently ignores custom code you write outside "settings" (c)In "settings", you can place any property in it you like

    (2)
    (a) From (1) above, if you need the submenu to route to a part of the page, in href (or whatever you call it) use "#sub1"; where "sub1" refers to a different route where nav is set to false.
    (b) If you want a hyperlink independent of routing, set href (or whatever you call it) to the url you desire (I used "zoldello.wordpress.com" in my example). No need to add a additional route

    (3) Follow the basic aurelia rules of building DOM (repeat, template etc)

    Here is an example:

    HTML file

    <li repeat.for="route of router.navigation">
      <!-- if route has no submenu -->
      <a href.bind="route.href" if.bind="!route.settings.subMenu">${route.title}</a>
    
      <!-- if route has submenu -->
      <a href.bind="javascript:;" class="dropdown-toggle" data-toggle="dropdown" 
      role="button" aria-haspopup="true" aria-expanded="false" if.bind="route.settings.subMenu">
      ${route.title} <span class="caret"></span></a>
    
      <ul if.bind="route.settings.subMenu">
        <li repeat.for="menu of route.settings.subMenu">
          <a href.bind="menu.href">${menu.title}</a>
        </li>
      </ul>
    </li>
    



    Javascript file

    configureRouter(config) {
      config.map([{
        route:'home',
        title:'Home',
        nav:true,
        module:'home'
      },{
        route:'top-menu',
        title:'Top Menu',
        nav:true,
        settings:{
          subMenu:[
            {href:'#/sub1', title:'Submenu 1'},
            {href:'zoldello.wordpress.com', title:'Submenu 2'},
            {href:'#/sub3', title:'Submenu 3'}
          ]
        }
      }, {
        route:'sub1',
        title:'Submenu 1',
        nav:false,
        moduleId:'module'
      }, {
        route:'sub2',
        title:'Submenu 2',
        nav:false,
        moduleId:'module'
      }, {
        route:'sub3',
        title:'Submenu 3',
        nav:false,
        moduleId:'module'
      }])
    }
    

  2. small fix for Phil’s answer

    html:

    <li class=" ${route.settings.subMenu ? '' : 'dropdown'} " repeat.for="route of router.navigation">
                    <!-- if route has no submenu -->
                    <a href.bind="route.href" if.bind="!route.settings.subMenu">${route.title}</a>
    
                    <!-- if route has submenu -->
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" if.bind="route.settings.subMenu">
                        ${route.title} <span class="caret"></span>
                    </a>
    
                    <ul class="dropdown-menu" if.bind="route.settings.subMenu">
                        <li repeat.for="menu of route.settings.subMenu">
                            <a href.bind="menu.href">${menu.title}</a>
                        </li>
                    </ul>
                </li>
    

    js

    configureRouter(config) { config.map([{
    route:'home',
    title:'Home',
    nav:true,
    moduleid:'home'  },{
    route:'top-menu',
    title:'Top Menu',
    nav:true,
    moduleid:'module'
    settings:{
      subMenu:[
        {href:'#/sub1', title:'Submenu 1'},
        {href:'zoldello.wordpress.com', title:'Submenu 2'},
        {href:'#/sub3', title:'Submenu 3'}
      ]
    } }, {
    route:'sub1',
    title:'Submenu 1',
    nav:false,
    moduleId:'module'  }, {
    route:'sub2',
    title:'Submenu 2',
    nav:false,
    moduleId:'module'  }, {
    route:'sub3',
    title:'Submenu 3',
    nav:false,
    moduleId:'module'  }])}
    
    Login or Signup to reply.
  3. I was looking for the same thing when I landed here. The above answers where helpful but didn’t take me as far as I needed to go. I learned of Bootstrap 3 dropdown sub menu missing and the work-arounds offered there but again needed something more.
    Then I found http://www.smartmenus.org/ which provides the responsiveness and functionality I need in a drop-down menu for Aurelia for our production app. I worked with their team to get a version of the skeleton app that works well.
    You can download it at http://www.smartmenus.org/files/demos/aurelia/SmartMenusDemo.zip.

    The app.ts file is similar to the example above but adds support for font-awesome icons:

    import {RouterConfiguration, Router} from 'aurelia-router';
    import 'jquery';
    import 'bootstrap';
    import 'smartmenus';
    import 'smartmenus-bootstrap';
    
    export class App {
        router: Router;
    
        configureRouter(config: RouterConfiguration, router: Router) {
            config.title = 'Aurelia';
            config.map([
                { route: ['', 'welcome'], name: 'welcome', moduleId: './welcome', nav: true, title: 'Welcome' },
                {
                    route: 'users', name: 'users', moduleId: './users', nav: true, title: 'Show Users',
                    settings: {
                        subMenu: [{ href: '#/users', title: 'Users', iconClass: 'fa fa-slideshare' },
                            { href: '#/usersTest', title: 'Test Users', iconClass: 'fa fa-street-view' },
                                    {
                                        href: '#', title: 'Sub Sub', iconClass: 'fa fa-medium', settings: {
                                            subMenu: [{ href: '#/child-router', title: 'Child Router', iconClass: 'fa fa-registered' },
                                                { href: '#/usersTest', title: 'Test Users', iconClass: 'fa fa-street-view' }]
                                        }
                                    },
                                    { href: '#/child-router', title: 'Child Router', iconClass: 'fa fa-registered' }]
                    }
                },
                { route: 'usersTest', name: 'usersTest', moduleId: './usersTest', nav: false, title: 'Test Users' },
                { route: 'child-router', name: 'childRouter', moduleId: 'child-router', nav: false, title: 'Child Router' },
                { route: 'users', name: 'users', moduleId: './users', nav: true, title: 'Github Users' }
            ]);
    
            this.router = router;
        }
    
        attached(): void {
            $.SmartMenus.Bootstrap.init();
        }
    
    }
    

    I implemented support for 4 levels of sub-menus in nav-bar.html:

    <template bindable="router">
        <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#top-level-nav">
                    <span class="sr-only">Toggle Navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">
                    <i class="fa fa-home"></i>
                    <span>${router.title}</span>
                </a>
            </div>
    
            <div class="collapse navbar-collapse" id="top-level-nav">
                <ul id="main-menu" class="nav navbar-nav ">
                    <li repeat.for="route of router.navigation" class="${row.isActive ? 'active' : ''} ${route.settings.subMenu ? 'dropdown' : ''}">
                        <!-- if route has no submenu -->
                        <a href.bind="route.href" if.bind="!route.settings.subMenu">${route.title}</a>
    
                        <!-- if route has submenu -->
                        <a if.bind="route.settings.subMenu" class="dropdown-toggle" data-toggle="dropdown"
                           role="button" aria-haspopup="true" aria-expanded="true">
                            ${route.title} <span class="caret"></span>
                        </a>
                        <ul if.bind="route.settings.subMenu" class="dropdown-menu">
                            <li repeat.for="l2SubMenu of route.settings.subMenu">
                                <a href.bind="l2SubMenu.href" if.bind="!l2SubMenu.settings.subMenu"><span class.bind="l2SubMenu.iconClass"> </span>&nbsp&nbsp${l2SubMenu.title}</a>
                                <a href.bind="l2SubMenu.href" if.bind="l2SubMenu.settings.subMenu" class="dropdown-toggle" data-toggle="dropdown"
                                   role="button" aria-haspopup="true" aria-expanded="true">
                                    <span class.bind="l2SubMenu.iconClass"> </span>&nbsp&nbsp${l2SubMenu.title} <span class="caret"></span>
                                </a>
                                <ul if.bind="l2SubMenu.settings.subMenu" class="dropdown-menu">
                                    <li repeat.for="l3SubMenu of l2SubMenu.settings.subMenu">
                                        <a href.bind="l3SubMenu.href" if.bind="!l3SubMenu.settings.subMenu"><span class.bind="l3SubMenu.iconClass"> </span>&nbsp&nbsp${l3SubMenu.title}</a>
                                        <a href.bind="l3SubMenu.href" if.bind="l3SubMenu.settings.subMenu" class="dropdown-toggle" data-toggle="dropdown"
                                           role="button" aria-haspopup="true" aria-expanded="true">
                                            <span class.bind="l3SubMenu.iconClass"> </span>
                                            &nbsp&nbsp${l3SubMenu.title} <span class="caret"></span>
                                        </a>
                                        <ul if.bind="l3SubMenu.settings.subMenu" class="dropdown-menu">
                                            <li repeat.for="l4SubMenu of l3SubMenu.settings.subMenu">
                                                <a href.bind="l4SubMenu.href"><span class.bind="l4SubMenu.iconClass"> </span>&nbsp&nbsp${l4SubMenu.title}</a>
                                            </li>
                                        </ul>
                                    </li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
    
                <ul class="nav navbar-nav navbar-right">
                    <li class="loader" if.bind="router.isNavigating">
                        <i class="fa fa-spinner fa-spin fa-2x"></i>
                    </li>
                </ul>
            </div>
        </nav>
    </template>
    

    As you can see, SmartMenus didn’t require much change to the app but provides us with great responsive multi-level drop down menus in Aurelia with the power of Bootstrap regardless of Bootstrap depreciating support for that.

    Hope this helps someone !

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search