6

I'm trying to do a recursive menu with angularJS, but I keep getting the fallowing error: Maximum call stack size exceeded

My directives:

angular.module("application").directive("navigation", [function () {
            return {
                restrict : 'E',
                replace : true,
                scope : {
                    menu : '='
                },
                template : '<ul><navigation-item ng-repeat="item in menu" submenu="item"></navigation-item></ul>',
                link : function ($scope, elem, attrs) {}
            }
        }
    ]);


angular.module("application").directive("navigationItem", [function () {

            return {
                restrict : 'E',
                replace : true,
                scope : {
                    submenu : '='
                },
                template : '<li>{{ submenu }}<navigation menu="submenu.Children"></navigation></li>',
                link : function ($scope, elem, attrs) {}
            }
        }
    ]);

My controller:

app.controller('myController', ['$scope', function (ng) {
        ng.menu = [{
            Id : 1,
            Nome : "Contact",
            Children : [{
                Nome : "Testing",
                Children : []
            }]
        }];
    }
]);

Here's how I'm using it:

<navigation menu="menu"></navigation>

http://jsfiddle.net/7sq3n/

hasser
  • 1,066
  • 1
  • 13
  • 24
WeaselBr
  • 116
  • 1
  • 1
  • 7

2 Answers2

15

There's 2 things here:

  1. You don't need 2 directives
  2. I had suspected that you would need to use the directive's compile function to get this to work since you're using the directive itself inside its own template, you'll also need to use the injectable $compile

I've used the ngIf directive in the template, you don't have to I just wanted to let you know and to warn you that you need to use AngularJS 1.1.5+ in order to use that directive.

Here's a JSFiddle I got working: http://jsfiddle.net/mikeeconroy/7sq3n/6/

.directive("navigation", ['$log','$compile',function ($log,$compile) {

    return {
        restrict: 'E',
        replace: true,
        scope: {
            menu: '='
        },
        template: '<ul><li ng-repeat="item in menu">{{item.Name}}<span ng-if="item.Children.length > 0"><navigation menu="item.Children"></navigation></span></li></ul>',
        compile: function (el) {
            var contents = el.contents().remove();
            return function(scope,el){
                $compile(contents)(scope,function(clone){
                    el.append(clone);
                });
            };
        }
    };

I cobbled this together with a little help from here: Recursion in Angular directives

UPDATE: http://jsfiddle.net/mikeeconroy/Z6sG9/2/ Solves multiple root element problem

Community
  • 1
  • 1
m.e.conroy
  • 3,508
  • 25
  • 27
  • 1
    Works fine with one root element, but when I tried to do with two root elements, it dod not show the child nodes. Fidlle: http://jsfiddle.net/7sq3n/7/ - Any suggestions? – WeaselBr Nov 18 '13 at 16:33
  • Looking into it now, very odd – m.e.conroy Nov 18 '13 at 16:49
  • 1
    http://jsfiddle.net/mikeeconroy/Z6sG9/2/ I don't know why breaking up the `$compile` statement makes it work but it does, maybe there is some behind the scenes race situation happening. – m.e.conroy Nov 18 '13 at 17:12
1

Dynamic, recursive navigation menu (navbar) using dynamic data with Angular & Bootstrap.

http://plnkr.co/edit/YqGcmcH6VQqr3rxOswnb

    <div ng-app="headerMenuApp">
    <div ng-controller="headerMenuListController">
        <nav id="headerNavigationMenuContainer" class="navbar navbar-default">
            <div class="container-fluid">

                <!-- Non-collapsing right-side menu items -->
                <div class="navbar-header pull-right">
                    <ul class="nav pull-left navbar-nav text-nowrap">
                        <li class="dropdown pull-right">
                            <a href="#" class="dropdown-toggle navbar-icon" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-question-circle"></i> &nbsp; Help <span class="caret"></span></a>
                            <ul class="dropdown-menu" role="menu">
                                <li><a href="#">Live Chat</a></li>
                                <li><a href="#">Help Topics</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>

                <!-- Collapsing left-side menu items -->
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed pull-left" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar" ng-init="navCollapsed = true" ng-click="navCollapsed = !navCollapsed">
                        <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="#">Logo</a>
                </div>

                <div id="navbar" class="collapse navbar-collapse" ng-class="!navCollapsed && 'in'">
                    <ul class="nav navbar-nav text-nowrap">
                        <leaf ng-repeat='leaf in tree' leaf='leaf'></leaf>
                    </ul>
                </div>

            </div>
        </nav>
    </div>
</div>
Jake H
  • 11
  • 1