How to recursively render JSON tree as HTML using AngularJS? - javascript

Suppose I have the following JSON structure in my javascript as a variable named myTree:
[
{"name": "A", "children": [
{"name": "C", "children": []},
{"name": "D", "children": []},
]
},
{"name": "B", "children": []}
]
I would like to use AngularJS to render it as the following HTML. How can I do it?
FYI, the tree can have arbitrary depth. I have shown only a very simple example here.
<ul>
<li>
A
<ul>
<li>C</li>
<li>D</li>
</ul>
</li>
<li>B</li>
</ul>

You should make recursive templates:
<script type="text/ng-template" id="item_template">
{{child.name}}
<ul>
<li ng-repeat="child in child.children" ng-include="'item_template'">
</li>
</ul>
</script>
<ul>
<li ng-repeat="child in myTree" ng-include="'item_template'">
</li>
</ul>
So, you will render 'infinite' levels of recursion, no only the first level.

Related

Filter angular js data source inside parent and child nodes

I have created a tree view in angular js using ng-repeat. I have also added a filter to filter my data source. I am able to filter the parent nodes and the resource nodes as what I expected, but my problem is I could not achieve the child node filtering as I expected. This is the picture of my current development status.
Img 4 Shows the current ststus of filtering my child nodes, but my exact requirement is like that in Img 5. i.e, on filtering a node if there is a child node present, only that child node and its parent should apperar, all the remaining child nodes must be hidden. What should I do for that. Here is my code snippet.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module("app", [])
.controller('MainController', function ($scope) {
$scope.ObjectData = { "name": "Main Object 1",
"ParentObject": [
{
"name": "Parent Object 1",
"ChildObject": [
{"name": "Child Object 11"},
{"name": "Child Object 12"}
]
},
{
"name": "Parent Object 2",
"ChildObject": [
{"name": "Child Object 21"},
{"name": "Child Object 22"}
]
}
],
"resources": [
"Resource 1", "Resource 2"
]
}
});
</script>
</head>
<body>
<div ng-app="app" ng-controller="MainController">
<input type="text" placeholder="search" ng-model="search">
<ul>
<li>
<a>
<span>{{ ObjectData.name }}</span>
</a>
<ul>
<li ng-repeat="subItem in ObjectData.ParentObject | filter:search">
<a>
<span>{{ subItem.name }}</span>
</a>
<ul>
<li ng-repeat="childItem in subItem.ChildObject">
<a>
<span>{{ childItem.name }}</span>
</a>
</li>
</ul>
</li>
</ul>
<ul>
<li ng-repeat="resources in ObjectData.resources | filter:search">
<a>
<span>{{ resources }}</span>
</a>
</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
After putting some more effort, I just created a simple logic to implement my requirement. I'm posting the solution because this might be helpful for someone.
I just added an ng-if inside my child item div. It displays the div content based on two condition.
The individual child object should be visible if the search key contains the characters inside the div.
All the child elements must be visible if the search key consists of the characters in the parent node.
Here is my final code.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module("app", [])
.controller('MainController', function ($scope) {
$scope.ObjectData = { "name": "Main Object 1",
"ParentObject": [
{
"name": "Parent Object 1",
"ChildObject": [
{"name": "Child Object 11"},
{"name": "Child Object 12"}
]
},
{
"name": "Parent Object 2",
"ChildObject": [
{"name": "Child Object 21"},
{"name": "Child Object 22"}
]
}
],
"resources": [
"Resource 1", "Resource 2"
]
};
$scope.IsChildObjectVisible = function(parent, child){
var searchKey = $scope.search;
var returnVal = true;
if(undefined != searchKey && null != searchKey && searchKey.length > 0){
returnVal = ((child.name.toLowerCase().indexOf(searchKey.toLowerCase()) > -1) || //Search key is present in a child node then that node is visible
(parent.name.toLowerCase().indexOf(searchKey.toLowerCase()) > -1)); //Search key is present in the parent node so all the child nodes inside that are visible
}
return returnVal;
}
});
</script>
</head>
<body>
<div ng-app="app" ng-controller="MainController">
<input type="text" placeholder="search" ng-model="search">
<ul>
<li>
<a><span>{{ ObjectData.name }}</span></a>
<ul>
<li ng-repeat="subItem in ObjectData.ParentObject | filter:search">
<a><span>{{ subItem.name }}</span></a>
<ul>
<li ng-repeat="childItem in subItem.ChildObject" ng-if="IsChildObjectVisible(subItem, childItem)">
<a><span>{{ childItem.name }}</span></a>
</li>
</ul>
</li>
</ul>
<ul>
<li ng-repeat="resources in ObjectData.resources | filter:search">
<a><span>{{ resources }}</span></a>
</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
HTML:
<li ng-repeat="childItem in subItem.ChildObject" ng-if='$filter(subItem.ChildObject, search).length == 0 || childItem.name == search'>
<a>
<span>{{ childItem.name }}</span>
</a>
</li>
Javascript:
.controller('MainController', function ($scope, $filter) {
$scope.$filter = $filter('filter');
//other stuff...
});

Angular UI tree implementation

Can any one provide with a plunker or any hint on how to use http://angular-ui-tree.github.io/angular-ui-tree/#/basic-example
with a json object like this
var list = [
{
"id": 1,
"title": "Parent",
"items": [
{
"id": 11,
"title": "child of Parent",
"items": [{
"id": 12,
"title": "inner child of Parent",
"items": [],
}],
},
]
}
]
We have a set of examples which can be seen on the website. You can view the data structure on the right hand side of every example.
See https://github.com/angular-ui-tree/angular-ui-tree/tree/master/examples
Lets look at the block in question
<div ui-tree>
<ol ui-tree-nodes="" ng-model="list">
<li ng-repeat="item in list" ui-tree-node>
<div ui-tree-handle>
{{item.title}}
</div>
<ol ui-tree-nodes="" ng-model="item.items">
<li ng-repeat="subItem in item.items" ui-tree-node>
<div ui-tree-handle>
{{subItem.title}}
</div>
</li>
</ol>
</li>
</ol>
</div>
item.items is also an array.
You know because the li nested below it is an ng-repeat looping through the values in item.items as subItem.

Loop through an array from JSON using Angular JS

I am trying to loop through an array from JSON and display the contents more like a side menu. I wrote something like
<ul ng-repeat="(key, value) in menuList.Menu">
<li>{{key}}</li>
<ul ng-repeat="(key, value) in value">
<li> {{key}}</li> //second key
<ul ng-repeat="(key, value) in value">
<li> {{key}}</li>
<ul ng-repeat="(key, value) in value">
<li> {{key}} : {{value}}</li>
</ul>
</ul>
</ul>
</ul>
The problem is my second key has both object and array. How do I display the value of Object and loop/ng-repeat just through the array. I cannot modify it with this as it will display the entire content of the array.
<li> {{key}} : {{value}}</li>
A part of my JSON for better understanding is given below:
{
"class": 99,
"mode" : 0,
"Menu": [{
"MenuNum": 1,
"MenuItems": [{
"ItemNum": 0,
"ItemDesc": "Main Menu",
"ActionCode": "-",
"ActionInst": ""
} , {
"ItemNum": 1,
"ItemDesc": "BBQ",
"ActionCode": "M",
"ActionInst": "0992"
}, {
"ItemNum": 2,
"ItemDesc": "Beverages",
"ActionCode": "M",
"ActionInst": "0992"
}]
},{
"MenuNum": 2,
"MenuItems": [{
"ItemNum": 0,
"ItemDesc": "Sub Menu",
"ActionCode": "-",
"ActionInst": ""
}, {
"ItemNum": 1,
"ItemDesc": "BBQTYPE1",
"ActionCode": "P",
"ActionInst": "0996"
}, {
"ItemNum": 2,
"ItemDesc": "BeveragesTYPE1",
"ActionCode": "P",
"ActionInst": "0998"
}]
}]
}
I want the sidebar more like
Presuming at the moment that you just want the ng-repeat logic, this may be what you are looking for:
<ul ng-repeat="topMenu in menuList.Menu">
<li>
{{$index}}
<ul>
<li>
MenuNum: {{topMenu.MenuNum}}
</li>
<li> MenuItems
<ul ng-repeat="submenu1 in topMenu.MenuItems">
<li>
{{$index}}
<ul>
<li>ItemNum: {{submenu1.ItemNum}}</li>
<li>ItemDesc: {{submenu1.ItemDesc}}</li>
<li>ActionCode: {{submenu1.ActionCode}}</li>
<li>ActionInst: {{submenu1.ActionInst}}</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
If you then want a relatively easy way to do the menu opening/closing, you would probably want to put all this into an Angular accordion. I can probably help you with that if you want.
It looks like you're trying to create a list with nested children. How about a recursive pattern which uses ng-include recursively to display all the nested children? Something like this:
<script type="text/ng-template" id="menuTree">
{{ menuItem.name }}
<ul ng-if="menuItem.children">
<li ng-repeat="menuItem in menuItem.children" ng-include="'menuTree'"></li>
</ul>
</script>
<ul>
<li ng-repeat="menuItem in menuItems" ng-include="'menuTree'"></li>
</ul>
I'm using a slightly different data structure to your code, but you should get the idea. Here's a demo: http://jsfiddle.net/mmmxh8kq/
EDIT:
If the data is as simple as the JSON you posted and you don't need a recursive menu, you could just try this:
<ul>
<li ng-repeat="menus in menuList.Menu">
{{ menus.MenuNum }}
<ul>
<li ng-repeat="menuItems in menus.MenuItems">
{{ menuItems.ItemDesc }}
</li>
</ul>
</li>
</ul>
Demo: http://jsfiddle.net/n4mo80od/

AngularJS: How to display nested objects?

I have following (json) object:
[
{
name: "Foo",
children: [{
name: "bar",
children:[{
...
}]
}]
}
]
There can be any number of children/objects in any level. Now I want to get following HTML Code:
<ul>
<li>Foo</li>
<li>
<ul>
<li>Bar</li>
</ul>
</li>
<ul>
But of course there could be 10 or more levels with 20 or more children per level.
Is there any way to do that? Thank you very much!
this should work, just replace json array with your data
<script type="text/ng-template" id="nodes_renderer.html">
{{node.name}}
<ul ng-model="node.children" ng-class="{hidden: collapsed}">
<li ng-repeat="node in node.children" ng-include="'nodes_renderer.html'">
</li>
</ul>
</script>
<div data-drag-enabled="false">
<ul>
<li ng-repeat="node in #*JSON ARRAY*#" ng-include="'nodes_renderer.html'">
</li>
</ul>
</div>

Using AngularJS to turn a multi-dimensional array into a multi level list

I am using AngularJS and trying to use ng-repeat or the like to take a multi-dimensional array and put it into the DOM as a mutli-level list.
From This:
var menuOptions = [
["Page One"],
["Page Two"],
["Page Three"],
["Page Four", ["Sub-Page 1", "Sub-Page 2", "Sub-Page 3"] ],
["Page Five"]
];
To This:
<ul>
<li>Page One</li>
<li>Page Two</li>
<li>Page Three</li>
<li>Page Four
<ul>
<li>Sub-Page 1</li>
<li>Sub-Page 2</li>
<li>Sub-Page 3</li>
</ul>
</li>
<li>Page Five</li>
</ul>
I was unable to find anything in the Angular JS Documentation and a search of the web came to no avail. I am aware that I can handle something like this with plain 'ol Javascript, or PHP but I would like to utilize some Angular JS thing like ng-repeat.
Any input is appreciated.
Thanks!
If you turn your array into the following
var menuOptions = [
["Page One", []],
["Page Two", []],
["Page Three", []],
["Page Four", ["Sub-Page 1", "Sub-Page 2", "Sub-Page 3"] ],
["Page Five", []]
];
You should be able to do this:
<ul>
<li ng-repeat='option in menuOptions'>
{{option[Ø]}}
<ul>
<li ng-repeat='suboption in option[1]'>{{suboption}}</li>
</ul>
<li>
</ul>
If you don't know the names of your keys, you can use this format...
JSON
{
"aclType": "combined",
"active": 1,
"attributes": {
"a6f8f9fb89ac4b2b12121c4ec4fa5441/#": [
"pub",
"sub",
"get",
"post",
"delete"
],
"a5f8f9eb89ac4b2b12121c4ec4fa8670/#": [
"pub",
"sub",
"get",
"post",
"delete"
]
}
}
You can loop like this:
<h2>Account Permissions</h2>
<ul>
<li>
<p><strong>Active:</strong> {{ acl.active}}</p>
</li>
<li ng-repeat="(key, data) in acl.attributes">
<p><strong>{{ key }}</strong></p>
<ul>
<li ng-repeat="permission in data">{{ permission }}</li>
</ul>
</li>
</ul>

Categories

Resources