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.