0

I need a bootstrap menu created from a tree json structure in angular. These two stackoverflow answers deal with each problem separately. I need to combine them:

Bootstrap 3 dropdown submenu (fiddle)

Sample Markup

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu" style="display: block; position: static; margin-bottom: 5px; *width: 180px;">
  <li class="menu-item dropdown dropdown-submenu">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Level 1</a>
    <ul class="dropdown-menu">
      <li class="menu-item ">
        <a href="#">Link 2</a>
      </li>
      <li class="menu-item dropdown dropdown-submenu">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Level 2</a>
        <ul class="dropdown-menu">
          <li>
            <a href="#">Link 3</a>
          </li>
          <li class="menu-item dropdown dropdown-submenu">
            <a ref="#" class="dropdown-toggle" data-toggle="dropdown">Level 3</a>
            <ul class="dropdown-menu">
              <li>
                <a href="#">Link 4</a>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

CSS

.dropdown-submenu {
  position: relative;
}

.dropdown-submenu>.dropdown-menu {
  top: 0;
  left: 100%;
  margin-top: -6px;
  margin-left: -1px;
  -webkit-border-radius: 0 6px 6px 6px;
  -moz-border-radius: 0 6px 6px 6px;
  border-radius: 0 6px 6px 6px;
}

.dropdown-submenu:hover>.dropdown-menu {
  display: block;
}

.dropdown-submenu>a:after {
  display: block;
  content: " ";
  float: right;
  width: 0;
  height: 0;
  border-color: transparent;
  border-style: solid;
  border-width: 5px 0 5px 5px;
  border-left-color: #cccccc;
  margin-top: 5px;
  margin-right: -10px;
}

.dropdown-submenu:hover>a:after {
  border-left-color: #ffffff;
}

.dropdown-submenu.pull-left {
  float: none;
}

.dropdown-submenu.pull-left>.dropdown-menu {
  left: -100%;
  margin-left: 10px;
  -webkit-border-radius: 6px 0 6px 6px;
  -moz-border-radius: 6px 0 6px 6px;
  border-radius: 6px 0 6px 6px;
}

Recursion in angular directives (fiddle)

module.factory('RecursionHelper', ['$compile', function($compile){
    var RecursionHelper = {
        compile: function(element){
            var contents = element.contents().remove();
            var compiledContents;
            return function(scope, element){
                if(!compiledContents){
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function(clone){
                    element.append(clone);
                });
            };
        }
    };

    return RecursionHelper;
}]);

module.directive("tree", function(RecursionHelper) {
    return {
        restrict: "E",
        scope: {family: '='},
        template: 
            '<p>{{ family.name }}</p>'+
            '<ul>' + 
                '<li ng-repeat="child in family.children">' + 
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(element) {
            return RecursionHelper.compile(element);
        }
    };
});

My attempt to merge both (fiddle)

module.directive("tree", function(RecursionHelper) {
  return {
    restrict: "E",
    scope: {
      family: '='
    },
    template: '<a href="#" ng-attr-class="{{family.children.length != 0 && \'dropdown-toggle\'}}" ng-attr-data-toggle="{{ family.children.length != 0 && \'dropdown\'}}">{{ family.name }}</a>' +
      '<ul class="dropdown-menu" ng-if="family.children.length!=0">' +
      '<li ng-attr-class="{{family.children.length != 0 && \'menu-item dropdown dropdown-submenu\'|| \'menu-item\'}}" ng-repeat="child in family.children">' +
      '<tree family="child"></tree>' +
      '</li>' +
      '</ul>',

    compile: function(element) {
      return RecursionHelper.compile(element);
    }
  };
});

As you can see, my attempt does not work.

Problem

Using Chrome developer tools I found out that Bootstrap submenu does not get along with having extra tags inside li elements.

So the following HTML code (adding <data-some-random-tag> after li) does not work (fiddle).

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu" style="display: block; position: static; margin-bottom: 5px; *width: 180px;">
  <li class="menu-item dropdown dropdown-submenu">
    <data-some-random-tag><!-- <---- **this tag was added** -->
      <a href="#" class="dropdown-toggle" data-toggle="dropdown">Level 1</a>
      <ul class="dropdown-menu">
        <li class="menu-item ">
          <a href="#">Link 2</a>
        </li>
        <li class="menu-item dropdown dropdown-submenu">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown">Level 2</a>
          <ul class="dropdown-menu">
            <li>
              <a href="#">Link 3</a>
            </li>
            <li class="menu-item dropdown dropdown-submenu">
              <a ref="#" class="dropdown-toggle" data-toggle="dropdown">Level 3</a>
              <ul class="dropdown-menu">
                <li>
                  <a href="#">Link 4</a>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </data-some-random-tag>
  </li>
</ul>

So the tree tag is breaking the bootstrap submenu. I think changing the directive type to an html comment could fix this. I know I can change a directive from

<span my-dir="exp"></span>

to

<!-- directive: my-dir exp -->

But <tree family="child"></tree> to <!-- directive: tree family child --> does not work. Also tried <!-- directive: tree family=child -->, <!-- directive: tree family="child" -->

I'm open to other possible solutions.

0

1 Answer 1

1

I followed up on this: Is it possible to make a Tree View with Angular?

Fiddle http://jsfiddle.net/82trw21a/1/

<script type="text/ng-template" id="tree_item_renderer.html">
  <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{data.name}}</a>

  <ul class="dropdown-menu">
    <li ng-if="data.children.length != 0" class="menu-item dropdown dropdown-submenu" ng-repeat="data in data.children" ng-include="'tree_item_renderer.html'"></li>
    <li ng-if="data.children.length == 0" class="menu-item" ng-repeat="data in data.children" ng-include="'tree_item_renderer.html'"></li>
  </ul>
</script>

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu" style="display: block; position: static; margin-bottom: 5px; *width: 180px;">
  <li class="menu-item dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Menu<b class="caret"></b></a>
    <ul class="dropdown-menu" ng-app="Application" ng-controller="TreeController">
      <li class="menu-item dropdown dropdown-submenu" ng-repeat="data in tree" ng-include="'tree_item_renderer.html'"></li>
    </ul>

  </li>
</ul>

Angular:

angular.module("myApp", []).
controller("TreeController", ['$scope', function($scope) {
  $scope.delete = function(data) {
    data.children = [];
  };
  $scope.add = function(data) {
    var post = data.children.length + 1;
    var newName = data.name + '-' + post;
    data.children.push({
      name: newName,
      children: []
    });
  };


  $scope.tree = [{
    name: "Level1",
    children: [{
      name: "Link1",
      children: []
    }, {
      name: "Level2",
      children: [{
        name: "Link3",
        children: []
      }, {
        name: "Level3",
        children: [{
          name: "Link4",
          children: []
        }]
      }]
    }]
  }];
}]);
Sign up to request clarification or add additional context in comments.

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.