# Using Bootstrap 4 with a multilevel dropdown nav menu

**URL:** <https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624>\
**Category:** Help Requests\
**Created:** [June 8, 2019, 5:54am UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624 "2019-06-08T05:54:15Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![si2030](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/si2030/32/275_2.png) [@si2030](https://discourse.aurelia.io/u/si2030)\
**Post date:** [June 8, 2019, 5:54am UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/1 "2019-06-08T05:54:15Z")

</div>

I have a multi level dropdown bootstrap 4 navbar. It works in a fashion but I have the problem in that if a page is selected from one of the multi levels rather than the immediate menu I loose the activate class.

Wondering if someone might guide me to how I can get activate on lower multi level options?

Here is the navmenu.html

```
<template>
<require from="./navmenu.scss"></require>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mainmenu mr-auto">
	<a class="navbar-brand" href="#/home">JobsLedger</a>
	<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
		<span class="navbar-toggler-icon"></span>
	</button>

	<div class="navbar-collapse collapse" id="navbarSupportedContent">
		<ul class="navbar-nav mr-auto">
			<li repeat.for="route of router.navigation">
				<a href.bind="route.href" if.bind="!route.settings.nav" class="menu-level-link ${route.isActive ? 'active' : ''}"><font-awesome-icon icon="${ route.settings.icon }"></font-awesome-icon> ${route.title}</a>
				
				<a href.bind="route.href" if.bind="route.settings.nav" class="menu-level-dropdown dropdown-toggle ${route.isActive ? 'active' : ''}" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					<font-awesome-icon icon="${ route.settings.icon }"></font-awesome-icon>
					${route.title} 
				</a>

				<ul if.bind="route.settings.nav" class="dropdown-menu" aria-labelledby="navbarDropdown" role="button">
					<li repeat.for="menu of route.settings.nav" class="${menu.settings.divider ? 'divider' : 'dropdown-submenu '}">
						<a href.bind="menu.href" if.bind="!menu.settings.nav" class="dropdown-submenu-link">
							<font-awesome-icon icon="${ menu.settings.icon }"></font-awesome-icon>
							${menu.title}
						</a>
						<a href.bind="menu.href" if.bind="menu.settings.nav" class="dropdown-toggle" data-toggle="dropdown" role="button">
							<font-awesome-icon icon="${ menu.settings.icon }"></font-awesome-icon>
							${menu.title} <span class="caret-right"></span>
						</a>

						<ul if.bind="menu.settings.nav" class="dropdown-menu" aria-labelledby="navbarDropdown">
							<li repeat.for="subMenu of menu.settings.nav" class="${subMenu.settings.divider ? 'divider' : 'dropdown-submenu '}">
								<a href.bind="subMenu.href" if.bind="!subMenu.settings.nav" class="dropdown-submenu-link">
									<font-awesome-icon icon="${ subMenu.settings.icon }"></font-awesome-icon>
									${subMenu.title}
								</a>
								<a href.bind="subMenu.href" if.bind="subMenu.settings.nav" class="dropdown-toggle" data-toggle="dropdown" role="button">
									<font-awesome-icon icon="${ subMenu.settings.icon }"></font-awesome-icon>
									${subMenu.title} <span class="caret-right"></span>
								</a>

								<ul if.bind="subMenu.settings.nav" class="dropdown-menu" aria-labelledby="navbarDropdown">
									<li repeat.for="lowestSubMenu of subMenu.settings.nav" class="${lowestSubMenu.settings.divider ? 'divider' : 'dropdown-submenu '}">
										<a href.bind="lowestSubMenu.href" if.bind="!lowestSubMenu.settings.divider" class="dropdown-submenu-link">
											<font-awesome-icon icon="${ lowestSubMenu.settings.icon }"></font-awesome-icon>
											${lowestSubMenu.title}
										</a>
									</li>
								</ul>

							</li>

						</ul>

					</li>

				</ul>

			</li>

		</ul>

		<ul class="nav navbar-nav navbar-right mr-auto">
			<li repeat.for="row of routes" if.bind="row.settings.pos == 'right'" class="${ row.isActive ? 'link-active' : '' }">
				<a href.bind="row.href" if.bind="!row.settings.nav">${ row.title }</a>

				<a href.bind="row.href" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"
					 if.bind="row.settings.nav">
					${row.title}
					<span class="caret"></span>
				</a>

				<ul if.bind="row.settings.nav" class="dropdown-menu">
					<li repeat.for="menu of row.settings.nav">
						<a href.bind="menu.href">${menu.title}</a>
					</li>
				</ul>
			</li>
			<li><a>Welcome ${userName}</a></li>
			<li><a href="#" click.delegate="logout()">Log Out</a></li>
		</ul>
	</div>
</nav>

```

You can see that at the top level I use a ternary function

class=“menu-level-link ${route.isActive ? ‘active’ : ‘’}”

…and it works for those menu items that are directly under the menu option but should I select a second or third level option the menu item looses its active class tag…

No idea how to fix this… Hope someone might have a solution

Simon

---

<div class="post-metadata">

**Author:** ![Sjaak](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sjaak/32/1377_2.png) [@Sjaak](https://discourse.aurelia.io/u/Sjaak)\
**Post date:** [June 8, 2019, 4:29pm UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/2 "2019-06-08T16:29:22Z")

</div>

So if I understand you correctly, what you’re looking for is a evaluation of whether the current route (row) is either active or recursively a route found in route.settings.nav is active.

This can be done with a simple value converter, something in the likes of (pseudo and untested):

```auto
export class ActiveRouteValueConverter {
   toView(route) {
     function evaluateRoute(route) {
        if (route.isActive) {
           return true;
        } else { 
          if (route.settings.nav) {
             return route.settings.nav.any(evaluateRoute);
          }
          else {
             return false;
          }
        }

        return evaluateRoute(route);
     }
   }
}

```

Next in your view you can test against the results of this using: `class="menu-level-link ${route | activeRoute ? ‘active’ : ‘’}"`

---

<div class="post-metadata">

**Author:** ![si2030](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/si2030/32/275_2.png) [@si2030](https://discourse.aurelia.io/u/si2030)\
**Post date:** [June 9, 2019, 4:01am UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/3 "2019-06-09T04:01:48Z")

</div>

> [@Sjaak](#):
>
> ${route | activeRoute ? ‘active’ : ‘’}

I reckon this will work however I am having trouble wiring it up… I looked at the documentation for value converters and then implemented it as follows:

Created the file “activeRoute.ts” in the same folder as “navemenu.html”.

Copied the code above (I shall work on this more later) but added console.log(“Gets Here!!”) at the very top before it does anything to see if it gets called…

Added `<require from="./activeRoute"></require>` to the top of navmenu.ts

It doesnt render now with the error:

Uncaught (in promise) Error: Parser Error: Unconsumed token ? at column 20 in expression [route | activeRoute ? ‘active’ : ‘’]  
at ParserImplementation.err (aurelia-binding.js:2857)  
at ParserImplementation.parseBindingBehavior (aurelia-binding.js:2392)  
at Parser.parse (aurelia-binding.js:2349)  
at TemplatingBindingLanguage.parseInterpolation (aurelia-templating-binding.js:835)  
at TemplatingBindingLanguage.inspectAttribute (aurelia-templating-binding.js:699)  
at ViewCompiler.\_compileElement (aurelia-templating.js:2976)  
at ViewCompiler.\_compileNode (aurelia-templating.js:2776)  
at ViewCompiler.\_compileNode (aurelia-templating.js:2798)  
at ViewCompiler.compile (aurelia-templating.js:2745)  
at HtmlBehaviorResource.compile (aurelia-templating.js:4258)  
err

I note that it did load the file activeRoute:

```
DEBUG [templating] importing resources for app/navmenu/navmenu.html 
(2) ["app/navmenu/navmenu.scss", "app/navmenu/activeRoute"]
     0: "app/navmenu/navmenu.scss"
     1: "app/navmenu/activeRoute"

```

Im not sure whats causing this… is it the fact the value converter is faulty or is something I have done.

---

<div class="post-metadata">

**Author:** ![si2030](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/si2030/32/275_2.png) [@si2030](https://discourse.aurelia.io/u/si2030)\
**Post date:** [June 9, 2019, 4:45am UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/4 "2019-06-09T04:45:53Z")

</div>

So it is loading the value converter… it fails on “?” in the ternary and I dont know why. . looked at the Aurelia Inspector at route and I see that it should work as “isActive” exists.

```
route: NavModel
▶ isActive: true
▶ title: "scheduler"
▶ href: "#/"
▶ relativeHref: ""
▶ settings: Object
▶ config: Object
▶ router: AppRouter
```

---

<div class="post-metadata">

**Author:** ![si2030](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/si2030/32/275_2.png) [@si2030](https://discourse.aurelia.io/u/si2030)\
**Post date:** [June 9, 2019, 4:59am UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/5 "2019-06-09T04:59:40Z")

</div>

> [@Sjaak](#):
>
> ${route | activeRoute ? ‘active’ : ‘’}

I changed activeRoute to the following (as simple as I could make it) and I still get that same error…

```
export class ActiveRouteValueConverter {
toView(route) {
	console.log("gets here!!")
	return route.isActive;
  }
}

```

I would have thought this would work…

---

<div class="post-metadata">

**Author:** ![Sjaak](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sjaak/32/1377_2.png) [@Sjaak](https://discourse.aurelia.io/u/Sjaak)\
**Post date:** [June 9, 2019, 2:19pm UTC](https://discourse.aurelia.io/t/using-bootstrap-4-with-a-multilevel-dropdown-nav-menu/2624/6 "2019-06-09T14:19:54Z")

</div>

> [@si2030](#):
>
> … it fails on “?” in the ternary and I dont know why. . looked at the Aurelia Inspector at route and I see that it s

My bad, the use of the value converter in my example is wrong. A value converter can convert between the bindingContext (viewmodel) and view. A valid use of the value converter would be something like this:  
`<a class="menu-level-link ${route | activeRoute:'active'}"> ${route.title}</a> "`

and in the value converter:

```auto
toView(route, conditionalResult) {
  if (.....) // validate if route is active
    return conditionalResult;
  else 
    return null;
}

```
