Reputation: 771
I need some help building a navigation bar with N elements.
I have a directive that looks like this:
angular.module('tool')
.directive('navigation', [function () {
return {
restrict: 'E',
controller: 'NavigationController',
templateUrl: '/Scripts/Directives/Navigation.html'
}
}]);
Navigation.html:
<ul class="nav navbar-nav" ng-repeat="NavItem in navitems">
<li>
<a href="{{NavItem.Href}}">{{NavItem.Name}}</a>
</li>
</ul>
The layout:
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div class="navbar-collapse collapse">
<navigation></navigation>
</div>
</div>
</div>
NavigationController:
angular.module('tool')
.controller('NavigationController', ['$scope', '$route', 'NavigationFactory', function ($scope, $route, NavigationFactory) {
$scope.$route = $route;
NavigationFactory.navigation().success(function (data) {
let nav = JSON.parse(data);
$scope.navitems = data.NavItems;
});
}]);
And finally the NavigationFactory:
angular.module('tool')
.factory('NavigationFactory', ['$http', function ($http) {
return {
navigation: function () {
return $http({ method: 'GET', url: '' });
}
}
}]);
Here is the JSON that it will be parsed:
{
"NavItems": [
{
"SubNav": [],
"Id": 1,
"Name": "FileSystem",
"ParentId": 0,
"IsAdminItem": false,
"Href": "/#/FileSystem"
},
{
"SubNav": [],
"Id": 2,
"Name": "Settings",
"ParentId": 0,
"IsAdminItem": false,
"Href": "/#/Settings"
}
]
}
What I have right now will work for this JSON but I want to also be able to dynamically generate the dropdown items if one of the NavItems has SubNav values.
I have tried to use my directive recursively by doing this:
<ul class="nav navbar-nav" ng-repeat="NavItem in navitems">
<li>
<a ng-hide="NavItem.SubNav.length > 0" href="{{NavItem.Href}}">{{NavItem.Name}}</a>
<div ng-show="NavItem.SubNav.length > 0" ng-switch>
<div ng-switch-when="true">
<div ng-init="navitems = NavItem.SubNav" ng-include="Navigation.html"></div>
</div>
</div>
</li>
</ul>
However, when I try to do that I don't get any errors it just doesn't show. Here is the test JSON with subnav that got me that error:
{
"NavItems": [
{
"SubNav": [],
"Id": 1,
"Name": "FileSystem",
"ParentId": 0,
"IsAdminItem": false,
"Href": "/#/FileSystem"
},
{
"SubNav": [
{
"SubNav": [],
"Id": 3,
"Name": "Logout",
"ParentId": 2,
"IsAdminItem": false,
"Href": "/#/Logout"
}
],
"Id": 2,
"Name": "Settings",
"ParentId": 0,
"IsAdminItem": false,
"Href": "/#/Settings"
}
]
}
How can I make it so that I am able to dynamically generate a Navigation bar with dropdowns using nth level architecture so that when I want to create more navitems I can just create them in the database and not have to worry about the front end?
Thanks!
EDIT
Eventually I want to have nested dropdowns so I don't want to have to keep adding ng-repeats in my directive.
Upvotes: 0
Views: 2469
Reputation: 771
Thank you eliagentili for putting me on the right track, however your answer did not exactly work for me so I modified it slightly.
Here is the new directive js:
angular.module('tool')
.directive('navigation', ['$compile', function ($compile) {
return {
restrict: 'E',
replace: true,
scope: {
item: '='
},
templateUrl: '/Scripts/Directives/Navigation.html'
}
}]);
and the new directive template:
<li ng-class="{'dropdown':item.SubNav.length > 0}">
<a ng-if="item.SubNav.length == 0" href="{{item.Href}}">{{item.Name}}</a>
<a ng-if="item.SubNav.length > 0" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true">{{item.Name}} <span class="caret"></span></a>
<ul class="dropdown-menu">
<navigation ng-repeat="SubItem in item.SubNav" item="SubItem"></navigation>
</ul>
</li>
and the layout:
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/#/">Project name</a>
</div>
<div class="navbar-collapse collapse" ng-controller="NavigationController">
<ul class="nav navbar-nav">
<navigation ng-repeat="SubMenuItem in navitems" item="SubMenuItem"></navigation>
</ul>
</div>
</div>
</nav>
Hope this helps someone else!
Upvotes: 0
Reputation: 619
Try changing your template for navigation directive declaring only the template for the li tag.
You can even declare a new directive specifically for that, and then create a recursive template like this:
menu-item.directive.html
<div ng-if="!$ctrl.item.SubNav"
ng-click="$ctrl.collapseOnClick()">
<a href="{{ $ctrl.item.Href }}">
{{ $ctrl.item.Name }}
</a>
</div>
<div ng-if="$ctrl.item.SubNav"
class="btn-group"
uib-dropdown
is-open="status.isopen"
ng-mouseover="status.isopen = true"
ng-mouseleave="status.isopen = false">
<a href="{{ $ctrl.item.Href }}"
ng-disabled="disabled">
<i class="fa fa-{{ $ctrl.item.icon }}"></i> {{ $ctrl.item.Name }} <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu" uib-dropdown-menu role="menu">
<menu-item ng-repeat="submenuItem in $ctrl.item.SubNav" item="submenuItem"></menu-item>
</ul>
</div>
Upvotes: 1