2

This question was asked by myself here:

Nesting angularjs directives recursively

and the inital problem was resolved, however, there appears to be a strange bug.

The code is here:

https://plnkr.co/edit/PhDvLZyWvyFThg57qZDV?p=preview

The double ng-repeat seems to be broken when calling a directive inside it. All of the data is being rendered on one element. I am guessing I have either made a mistake, or this is to do with the order angular pushes items into the digest cycle. The structure should be:

1
    1.1
        1.1.1
        1.1.2
        1.1.3
    1.2
        1.2.1
        1.2.2
        1.2.3
    1.3
        1.3.1
        1.3.2
        1.3.3
2
    2.1
        2.1.1
        2.1.2
        2.1.3
    2.2
        2.2.1
        2.2.2
        2.2.3
    2.3
        2.3.1
        2.3.2
        2.3.3

but is coming out as:

1
2
    2.1
    2.2
    2.3
        2.3.1
        2.3.2
        2.3.3
        2.2.1
        2.2.2
        2.2.3
        2.1.1
        2.1.2
        2.1.3
        1.3.1
        1.3.2
        1.3.3
        1.2.1
        1.2.2
        1.2.3
        1.1.1
        1.1.2
        1.1.3
    1.1
    1.2
    1.3

index.html

<!DOCTYPE html>
<html>

  <head>
    <script data-require="[email protected]" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="MainCtrl">
    <ul class="nav navbar-nav">
      <li ng-repeat="menu in menus">
        <button class="btn btn-default dropdown-toggle" type="button">
          <span ng-bind="menu.Text"></span>
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li menu-entry menus="menu.SubMenus"></li>
        </ul>
      </li>
    </ul>
  </body>

</html>

menu-entry.html

<li ng-repeat="menu in menus">
    <a ng-if="menu.SubMenus.length===0" ng-bind="menu.Text"></a>
    <button ng-if="menu.SubMenus.length>0" type="button" ng-bind="menu.Text">
        <span class="caret caret-right"></span>
    </button>
    <ul ng-if="menu.SubMenus.length>0" class="dropdown-menu" role="menu">
        <li menu-entry menus="menu.SubMenus"></li>
    </ul>
</li>

script.js

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope) {
  $scope.menus = [
    { Text: '1', SubMenus: [
      { Text: '1.1', SubMenus: [{Text:'1.1.1',SubMenus:[]},{Text:'1.1.2',SubMenus:[]},{Text:'1.1.3',SubMenus:[]}]},
      { Text: '1.2', SubMenus: [{Text:'1.2.1',SubMenus:[]},{Text:'1.2.2',SubMenus:[]},{Text:'1.2.3',SubMenus:[]}]},
      { Text: '1.3', SubMenus: [{Text:'1.3.1',SubMenus:[]},{Text:'1.3.2',SubMenus:[]},{Text:'1.3.3',SubMenus:[]}]}
      ]},
    { Text: '2', SubMenus: [
    { Text: '2.1', SubMenus: [{Text:'2.1.1',SubMenus:[]},{Text:'2.1.2',SubMenus:[]},{Text:'2.1.3',SubMenus:[]}]},
    { Text: '2.2', SubMenus: [{Text:'2.2.1',SubMenus:[]},{Text:'2.2.2',SubMenus:[]},{Text:'2.2.3',SubMenus:[]}]},
    { Text: '2.3', SubMenus: [{Text:'2.3.1',SubMenus:[]},{Text:'2.3.2',SubMenus:[]},{Text:'2.3.3',SubMenus:[]}]}
    ]},
    ];
});

app.directive('menuEntry', function() {
        var cFn = ['$scope', function ($scope) {

        }];

        var lFn = function (scope, element, attr, ctrl, transclude) {
        };

        return {
            restrict: 'A',
            replace: true,
            templateUrl: 'menu-entry.html',
            controller: cFn,
            link: lFn,
            scope: {
                menus: '='
            }
        };
});
4
  • why you still kept replace: true any special reason? Commented Mar 21, 2016 at 21:10
  • It's very good to include a plunkr for easy debugging, but always include the relevant code in the question as well. This is because a question must be self-contained: that link may break at some point in the future. Commented Mar 21, 2016 at 21:12
  • @PankajParkar because then you would have ul > li > li. With replace it would be ul > li Commented Mar 21, 2016 at 21:13
  • 1
    @wvdz Added. Appreciate the advice. I'm never sure what is best practicing when adding long examples of code, as sometimes it could dissuade people from answering when it looks too complex at a glance. Commented Mar 21, 2016 at 21:20

1 Answer 1

3

Move the ul that is just outside of the menu-entry directive and put it inside of the directive template. Template should look like this:

<ul>
<li ng-repeat="menu in menus">
    <a ng-if="menu.SubMenus.length===0" ng-bind="menu.Text"></a>
    <button ng-if="menu.SubMenus.length>0" type="button" ng-bind="menu.Text">
        <span class="caret caret-right"></span>
    </button>
    <ul ng-if="menu.SubMenus.length>0" class="dropdown-menu" role="menu">
        <li menu-entry menus="menu.SubMenus"></li>
    </ul>
</li>
</ul>
Sign up to request clarification or add additional context in comments.

3 Comments

very much appreciated, but before I mark this as the answer, would you be able to add what the problem was with the original code and why this works?
The problem with your original code was that the resulting DOM had a nested structure of ul > li > li instead of just ul > li. Moving the <ul> inside of the template removed that extra li level
It clearly works, but would it have been ul > li > li before? As replace was true.

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.