I have the following data structure for items in my sidemenu, in an Angular app based on a paid-for web site theme. The data structure is my own, and the menu is derived fro
You can achieve this simply by including a javascript template and template include using ng-include
define javascript template
<script type="text/ng-template" id="menu.html">...</script>
and include it like:
<div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
Example: In this example I used basic html without any class you can use classes as you need. I just shown basic recursion structure.
In html:
<ul>
<li ng-repeat="item in menuItems">
<a href="{{item.href}}">
<span>{{item.text}}</span>
</a>
<div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
</li>
</ul>
<script type="text/ng-template" id="menu.html">
<ul>
<li ng-repeat="item in item.subItems">
<a href="{{item.href}}">
<span>{{item.text}}</span>
</a>
<div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
</li>
</ul>
</script>
PLUNKER DEMO
Before using templates with ng-include
or writing your own directive, I would suggest that you consider using an existing tree component implementation.
The reason is that from your description, that's exactly what you need. You have a hierarchical tree-like data structure that you want to display. It sounds obvious to me that you need a tree component.
Take a look at the following implementations (1st one preferable):
https://github.com/angular-ui-tree/angular-ui-tree
https://github.com/wix/angular-tree-control
http://ngmodules.org/modules/angular.treeview
All of the above require only that you do a minor adjustment to your model, or alternatively, use a proxy model.
If you do insist on implementing it by yourself (and no matter how you end up doing it, essentially you still will be implementing a tree component from scratch), I would suggest the directive approach as proposed in previous answers. Here's how I'd do it:
var app=angular.module('MyApp', []);
app.controller('MyCtrl', function($scope, $window) {
$scope.menuItems = [
{
"isNavItem": true,
"href": "#/dashboard.html",
"text": "Dashboard"
},
{
"isNavItem": true,
"href": "javascript:;",
"text": "AngularJS Features",
"subItems": [
{
"href": "#/ui_bootstrap.html",
"text": " UI Bootstrap"
}
]
},
{
"isNavItem": true,
"href": "javascript:;",
"text": "jQuery Plugins",
"subItems": [
{
"href": "#/form-tools",
"text": " Form Tools"
},
{
"isNavItem": true,
"href": "javascript:;",
"text": " Datatables",
"subItems": [
{
"href": "#/datatables/managed.html",
"text": " Managed Datatables"
}
]
}
]
}];
});
app.directive('myMenu', ['$compile', function($compile) {
return {
restrict: 'E',
scope: {
menu: '='
},
replace: true,
link: function(scope, elem, attrs) {
var items = $compile('<my-menu-item ng-repeat="item in menu" menu-item="item"></my-menu-item>')(scope);
elem.append(items);
},
template: '<ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200" ng-class="{\'page-sidebar-menu-closed\': settings.layout.pageSidebarClosed}"></ul>'
};
}]);
app.directive('myMenuItem', [function() {
return {
restrict: 'E',
scope: {
menuItem: '='
},
replace: true,
template: '<li ng-class="{\'start\': item.isStart, \'nav-item\': item.isNavItem}"><a href="{{menuItem.href}}" ng-class="{\'nav-link nav-toggle\': menuItem.subItems && menuItem.subItems.length > 0}"> <span class="title">{{menuItem.text}}</span></a><my-menu menu="menuItem.subItems"></my-menu></li>'
};
}]);
<div ng-app="MyApp" ng-controller="MyCtrl">
<my-menu menu="menuItems"></my-menu>
</div>
Here's a working CodePen example: http://codepen.io/eitanfar/pen/oxZrpQ
Hope this helps.
You can simply use ng-include to make a partial and call it recursively: Partial should be something like this:
<ul>
<li ng-repeat="item in item.subItems">
<a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
<span class="title">{{item.text}}</span>
</a>
<div ng-switch on="item.subItems.length > 0">
<div ng-switch-when="true">
<div ng-init="subItems = item.subItems;" ng-include="'partialSubItems.html'"></div>
</div>
</div>
</li>
</ul>
And your html:
<ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200" ng-class="{'page-sidebar-menu-closed': settings.layout.pageSidebarClosed}">
<li ng-repeat="item in menuItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
<a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
<span class="title">{{item.text}}</span>
</a>
<ul ng-if="item.subItems && item.subItems.length > 0" class="sub-menu">
<li ng-repeat="item in item.subItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
<a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
<span class="title">{{item.text}}</span>
</a>
<div ng-switch on="item.subItems.length > 0">
<div ng-switch-when="true">
<div ng-init="subItems = item.subItems;" ng-include="'newpartial.html'"></div>
</div>
</div>
</li>
</ul>
</li>
</ul>
Here is the working plunker http://plnkr.co/edit/9HJZzV4cgacK92xxQOr0?p=preview
Do you mean something like this? http://jsfiddle.net/uXbn6/3639/
angular.module("myApp", []).controller("TreeController", ['$scope',function($scope) {
$scope.menuItems = [{
"isNavItem": true,
"href": "#/dashboard.html",
"text": "Dashboard"
}, {
"isNavItem": true,
"href": "javascript:;",
"text": "AngularJS Features",
"subItems": [{
"href": "#/ui_bootstrap.html",
"text": " UI Bootstrap"
}, {
"isNavItem": true,
"href": "javascript:;",
"text": "AngularJS Features",
"subItems": [{
"href": "#/ui_bootstrap.html",
"text": " UI Bootstrap"
}]
}]
}, {
"isNavItem": true,
"href": "javascript:;",
"text": "jQuery Plugins",
"subItems": [{
"href": "#/form-tools",
"text": " Form Tools"
}, {
"isNavItem": true,
"href": "javascript:;",
"text": " Datatables",
"subItems": [{
"href": "#/datatables/managed.html",
"text": " Managed Datatables"
}]
}]
}];
}]);
<script type="text/ng-template" id="tree_item_renderer.html">
<a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
<span class="title">{{item.text}}</span>
</a>
<ul ng-if="item.subItems && item.subItems.length > 0" class="sub-menu">
<li ng-repeat="item in item.subItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}" ng-include="'tree_item_renderer.html'"></li>
</ul>
</script>
<div ng-app="myApp" ng-controller="TreeController">
<ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200" ng-class="{'page-sidebar-menu-closed': settings.layout.pageSidebarClosed}">
<li ng-repeat="item in menuItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}" ng-include="'tree_item_renderer.html'"></li>
</ul>
</div>