AngularJS multi-level drop-down menu for a menu structure created from a recursive directive

I have a divorced marinade here. I have to get my layered navigation menu from a web service call.

Since my navigation menu can contain an infinite number of submenus in it, I had to use a recursive directive to create my parent / child navigation structure. Now I am trying to understand how to turn it into the functional structure of dropmenu. I looked at angularui-bootstrap and they have a Dropdown Toggle that has some basic dropmenu functions, but since I used a recursive directive, my menu structure already has angularjs generated by css classes attached to them. Angular fall css classes that are different from my generated angularjs classes .... here!

<ul> <li ng-repeat="parent in parents" class="ng-scope"> <recursive-list-item on-node-click="onNodeClickFn(node)" parent="parent" class="ng-isolate-scope ng-scope"> <a data-ng-click="onNodeClick({node: parent})" href="javascript:void(0)" class="ng-scope ng-binding">Clothes</a> <!-- ngIf: parent.children.length > 0 --> <ul data-ng-if="parent.children.length &gt; 0" class="ng-scope"> <!-- ngRepeat: child in parent.children --> <li ng-repeat="child in parent.children" class="ng-scope"> <recursive-list-item data-on-node-click="onNodeClickFn(node)" data-parent="child" class="ng-isolate-scope ng-scope"> <a data-ng-click="onNodeClick({node: parent})" href="javascript:void(0)" class="ng-scope ng-binding">Gortex Jackets</a> <!-- ngIf: parent.children.length > 0 --> </recursive-list-item> </li> <!-- end ngRepeat: child in parent.children --> ... ... ... </ul> </recursive-list-item> </li> <!-- end ngRepeat: child in parent.children --> ... ... </ul> 

This was an example html that is generated as the final output for my recursive navigation menu. Having set all the ng-click submenus this way, they have the same scope as the main controller (all this is a dandy, except that it does not look like dropmenu)

Here is an example dropmenu structure for angularjs-bootstrap

 <li class="dropdown" ng-controller="DropdownCtrl"> <a class="dropdown-toggle"> Click me for a dropdown, yo! </a> <ul class="dropdown-menu"> <li ng-repeat="choice in items"> <a>{{choice}}</a> </li> </ul> </li> 

It has a very large css class structure than mine, so the β€œdropdown” angularjs-bootstrap will not work with mine.

Does anyone have any suggestions for me? Keep in mind that since I get my navigation structure via json via the webservice call, I have to use recursive corner elements to create the parent / child menu structure.

If someone gets confused in my html directive generated here, I can show my custom directive code, but I won’t, unless it is requested for brevity. My custom directory code only works to create a navigation structure and saves all the directive scope associated with the main area of ​​the controller (ie: Press "Asset"), but does not have a style / scroll.

My Non Functional Menu Navigation

***** UPDATE ******** I created a plunker replication that is almost the same. In my project, I got the navigation menu data from angularjs service, which will make a webservice call to rest the webservice on my server, but I don’t have it, so I just manually created json for each of my services, which calls REST web service calls. The important part is the recursive directive. Below you will find a link to the plunker project. Can someone help me?

Plunker Project ------------------------- ----------------------- -------------

************* NEW UPDATE ***************** Comment from Charlietfl that I can just have several css classes in my dropview structure. I am trying to do this with angularui-bootstrap. I followed the instructions to add this to my project and created a new Plunker project, based on the old plunker project, but with additional dropmenu css classes added to the navigation structure. Here is the Plunker project: Plunker Project

Navigation items are still visible in the DOM, but they are not visible. I looked at css for the first ul element and it as such:

 *, *:before, *:after { -moz-box-sizing: border-box; } *, *:before, *:after { -moz-box-sizing: border-box; } .dropdown-menu { background-clip: padding-box; background-color: #FFFFFF; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176); display: none; float: left; font-size: 14px; left: 0; list-style: none outside none; margin: 2px 0 0; min-width: 160px; padding: 5px 0; position: absolute; top: 100%; z-index: 1000; } 

It was obtained from the official css boot file. Not sure why this is not visible. Not sure if this will help, but here is the css for the very next li element after ul

 *, *:before, *:after { -moz-box-sizing: border-box; } *, *:before, *:after { -moz-box-sizing: border-box; } .dropdown { position: relative; } .dropup, .dropdown { position: relative; } li { line-height: 20px; } *, *:before, *:after { -moz-box-sizing: border-box; } 

Keep in mind that you need to go to the plunker page to see the updated code, starting from the moment I added the css tags needed for angularui-bootstrap. To see invisible navigational elements, you need something like Firebug to see the DOM.

Here is an example of some final html output (from the DOM) from my update to try to work with the angularui-bootstrap css classes.

 ... <li ng-repeat="child in parent.children" class="dropdown ng-scope"> <recursive-list-item data-on-node-click="onNodeClickFn(node)" data-parent="child" class="ng-isolate-scope ng-scope"> <a class="dropdown-toggle ng-scope ng-binding" href="javascript:void(0)">Kids Clothes</a> ... 

I suspect that the reason the angularui-bootstrap function does not work is due to the "recursive-list-item .." element, which is the child of the "li" element and the parent element is the "a" element. Is this conjecture correct?

+7
javascript angularjs angularjs-directive angularjs-bootstrap
source share
1 answer

This is what I use and it has many additional features that are very nice. See Using $scope.menu , and what happens when expanding a drop-down list - you can put headers, dividers, and even join click functions. Note that you can nest as many ul as you want, and although toggle does work, it is useless since clicking to open the submenu will hide its parent. As far as I know, you will need to create your own javascript handler or custom css using hovers if you want a deeper nesting in the menu.

Live demo here (click).

 <nav> <div menu="menu"></div> <!-- the element here doesn't matter --> </nav> 

JS:

 var app = angular.module('myApp', ['ui.bootstrap']); app.directive('menu', function() { return { restrict: 'A', scope: { menu: '=menu', cls: '=ngClass' }, replace: true, template: '<ul><li ng-repeat="item in menu" menu-item="item"></li></ul>', link: function(scope, element, attrs) { element.addClass(attrs.class); element.addClass(scope.cls); } }; }); app.directive('menuItem', function($compile) { return { restrict: 'A', replace: true, scope: { item: '=menuItem' }, template: '<li active-link><a href={{item.href}}>{{item.title}}</a></li>', link: function (scope, element, attrs) { if (scope.item.header) { element.addClass('nav-header'); element.text(scope.item.header); } if (scope.item.divider) { element.addClass('divider'); element.empty(); } if (scope.item.submenu) { element.addClass('dropdown'); var text = element.children('a').text(); element.empty(); var $a = $('<a class="dropdown-toggle">'+text+'</a>'); element.append($a); var $submenu = $('<div menu="item.submenu" class="dropdown-menu"></div>'); element.append($submenu); } if (scope.item.click) { element.find('a').attr('ng-click', 'item.click()'); } $compile(element.contents())(scope); } }; }); app.controller('myCtrl', function($scope) { $scope.menu = [ { "title": "Home", "href": "#" }, { "title": "About", "href": "about" }, { "title": "History", "href": "about/history" }, { "title": "Contact", "href": "contact" }, { "title": "Other things - in a list. (Click here)", "submenu": [ { "header": "Sample Header" }, { "title": "Some Link", "href": "some/place" }, { "title": "Another Link", "href": "some/other/place" }, { "divider": "true" }, { "header": "Header 2" }, { "title": "Again...a link.", "href": "errrr" }, { "title": "Nest Parent", "submenu": [ { "title": "nested again", "href": "nested/again" }, { "title": "me too", "href": "sample/place" } ] } ] } ]; }); 

Update for nested drop-down list:

Live demo here (click).

 .dropdown-menu .dropdown-menu { margin: 0; left: 100%; top: -5px; } .dropdown-menu li:hover .dropdown-menu { display: block; } 
+6
source share

All Articles