0

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.

1
  • do a web search for angular recursive directive or template. Will find lots of results Commented Oct 30, 2016 at 16:15

2 Answers 2

1

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>
Sign up to request clarification or add additional context in comments.

Comments

0

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!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.