I am working with angularjs and I have this response from my service and Its coming as tree and I am representing that data to the angular tree. this object have 4 main children, name and id. but these children and their children also have children, name and id. What I want is no matter which child I click, I always want to access the value of main root parent name thats "node1" "node2" "node3" as name so i know what is my main parent and whats parent under im clicking.
$scope.loadOrganizationTree = function () {
userManagementFactory.getOrganizationTree()
.success(function(data, status) {
if (JSON.stringify(data.statusType).indexOf("success") > -1) {
$scope.dataForTheTree = data.statusMsg;
}
} else {
$scope.setResponseMsgs(data, status);
}
}).error(function(data, status) {
$scope.userErrorMsg = data.statusMsg;
$scope.showErrorMSg = true ;
});
<div treecontrol class="tree-light accordion-org-tree"
style="height: 609px !important;" tree-model="dataForTheTree"
order-by="name" reverse-order="false" options="treeOptions"
on-selection="showSelected(node, selected, $parentNode, $index, $first, $middle, $last, $odd, $even)"
selected-node="node1" filter-expression="userProfileOrgSearch">
{{node.name}}
</div>
[
{
"id": 1,
"name": "node1",
"children": [
{
"id": 11,
"name": "node1.1",
"children": [
{
"id": 111,
"name": "node1.1.1",
"children": []
}
]
},
{
"id": 12,
"name": "node1.2",
"children": []
}
]
},
{
"id": 2,
"name": "node2",
"children": [
{
"id": 21,
"name": "node2.1",
"nodes": []
},
{
"id": 22,
"name": "node2.2",
"nodes": []
}
]
},
{
"id": 3,
"name": "node3",
"children": [
{
"id": 31,
"name": "node3.1",
"children": []
}
]
}
]
So far I have tried accessing with $parentnode but its not working out for me. Please let me know the solution.
Thanks in advance.
After loading the data you fill $scope.dataForTheTree. Then you can walk through the tree and set the root of each node.
I coded this for you using a var dataForTheTree with your example data.
After running the below, each node has a root property set with it's root node.
var setRoot = function(elementWithChildren, root) {
elementWithChildren.root = root;
if (elementWithChildren.children != null) {
angular.forEach(elementWithChildren.children, function(child) { setRoot(child, root); });
}
};
angular.forEach(dataForTheTree, function(rootNode) { setRoot(rootNode, rootNode); });
we take each node of the tree and call the setRoot() function. which then calls the setRoot function for each of it's children.
Recursive.
Related
I have a following JSON Structure which I need to parse in React to build a side menu for an app.
var a = [
{"name":"John",
"subMenus":[{"First":[{"name":"Vulnerability","to":"/johnvulner"},
{"name":"Open Roles","to":"/johnopenRoles"}
]},
{"Second":[{"name":"Some People","to":"/johnpeople"},
{"name":"Another People","to":"/johnanotherpeople"}
]}],
},
{"name":"Sarah",
"subMenus":[{"First":[{"name":"Vulnerability","to":"/sarahvulner"},
{"name":"Open Roles","to":"/sarahopenRoles"}
]},
{"Second":[{"name":"Some People","to":"/sarahsomepeople"},
{"name":"Another People","to":"/sarahanotherpeople"}
]}],
}];
The output needed for the nested side menu should be as follows -
John
First
Vulnerability
Open Roles
Second
Some People
Another People
Sarah
First
Vulnerability
Open Roles
Second
Some People
Another People
Is there a simple way using array.map function to achieve this since I am building this menu inside an HTML div.
You can create it very easily by using the following code
let a = [{
"name": "John",
"subMenus": [{
"First": [{
"name": "Vulnerability",
"to": "/johnvulner"
},
{
"name": "Open Roles",
"to": "/johnopenRoles"
}
]
},
{
"Second": [{
"name": "Some People",
"to": "/johnpeople"
},
{
"name": "Another People",
"to": "/johnanotherpeople"
}
]
}
],
},
{
"name": "Sarah",
"subMenus": [{
"First": [{
"name": "Vulnerability",
"to": "/sarahvulner"
},
{
"name": "Open Roles",
"to": "/sarahopenRoles"
}
]
},
{
"Second": [{
"name": "Some People",
"to": "/sarahsomepeople"
},
{
"name": "Another People",
"to": "/sarahanotherpeople"
}
]
}
],
}
];
var menuItems = []
a.map((menu) => {
var submenus = []
menu.subMenus.map((submenu) => {
let keys = Object.keys(submenu);
keys.map( key => {
var keyValues=[]
if (submenu[key]){
submenu[key].map((item) => {
keyValues.push(item.name)
})
submenus.push({
[key]: keyValues
})
}
})
})
let thekey=menu.name
menuItems.push({
[thekey]: submenus
})
})
console.log(menuItems)
Update: Code updated for a any key fetch..
I am trying to alter the json in snippet to a tree structure just like in https://www.primefaces.org/primeng/#/treetable (below is the sample i expect too). I understand it involves recursion but I ain't sure how to deeply link each.
The output i expect is something like below. The json whose parent is true becomes the root. If the root has values, the json corresponding to id of the value is pushed to children array with a json object "data". Again if that json has values, the json correspond to the id of value is pushed to children array with a json object "data and so on.
The code i have written is just a initial phase. Need help on how nesting can be done through iteration.
[
{
"data": {
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P001",
"type": "File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P002",
"type": "Image",
"values": [
]
}
}
]
}
]
},
{
"data": {
"parent": true,
"id": "S000",
"type": "Something",
"values": [
]
}
}
]
var junkdata=[
{
"parent": false,
"id": "P001",
"type":"File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
{
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}]
},
{
"parent": false,
"id": "P002",
"type": "Image",
"values":[]
},
{
"parent": true,
"id": "S000",
"type": "Something",
"values":[]
}];
var parentDatas=junkdata.filter((x)=>x.parent==true);
if(parentDatas.length>0){
var finalResponse=parentDatas.map((parentData)=>{
var resultJson={};
resultJson.data=parentData;
if(parentData.values.length>0){
resultJson.children=[];
for(var i of parentData.values){
var child=junkdata.find((x)=>x.id==i.id);
if(child){
var jsonObj={};
jsonObj.data=child;
resultJson.children.push(jsonObj);
}
}
}
return resultJson;
})
}
console.log(JSON.stringify(finalResponse));
Basically, we can start with this to process the root nodes:
let tree = yourData.filter(x => x.parent).map(process);
where process is the recursive function that processes a given node:
let process = node => ({
id: node.id,
type: node.type,
children: node.values.map(x => process(
yourData.find(y => y.id === x.id)))
});
For each id in node.values, it locates a node with that id and recursively calls process on it. Once all child nodes are dealt with, process collects them into an array and returns the newly formatted object.
This is the general recursion pattern for working with graph-alike structures, where you have "nodes" somehow connected to other "nodes":
function F (N: node) {
for each node M which is connected to N {
F (M) <--- recursion
}
result = do something with N
return result
}
I have an array which looks like this:
[
{
"boxes": [
{
"id": 2,
"content": {
"name": "ABC",
"details": "some details for abc"
}
}
]
},
{
"boxes": [
{
"id": 3,
"content": {
"name": "XYZ",
"details": "some details for xyz"
}
},
{
"id": 4,
"content": {
"name": "UVW",
"details": "some details for uvw"
}
}
]
},
{}
]
And I have a variable: let id = 3
I want to be able to search through the nested array "boxes" to find the content property of the object that have the given id. Such that the result is:
{
"name": "XYZ",
"details": "some details for xyz"
}
Till now I have gathered that I can use a combination forEach and .filter do find this. But I'm not sure how. Also, I have control over the original data. So, if there's a better way to store the original data, I will be glad to have suggestions.
Actually I did attempt but got stuck:
Let's say the original array is called house.
let matches = []
let id = 3
house.forEach(function(e) {
matches = matches.concat(e.boxes.filter(function(b) {
return (b.id === id);
}));})
console.log(matches[0].content)
You could use map method by passing a callback function as argument. The scope of map method is to get all items from boxes array.
Also, I'm using filter(Boolean) statement in order to remove undefined value for those items which doesn't have boxes as property.
At least, use find method in order to get the desired output result.
let arr = [ { "boxes": [ { "id": 2, "content": { "name": "ABC", "details": "some details for abc" } } ] }, { "boxes": [ { "id": 3, "content": { "name": "XYZ", "details": "some details for xyz" } }, { "id": 4, "content": { "name": "UVW", "details": "some details for uvw" } } ] }, {} ]
let id = 1;
let result = [].concat(...arr.map(item => item.boxes))
.filter(Boolean)
.find(({id}) => id == id).content;
console.log(result);
First you need to put boxes object into one array, it seems it just has couple extra levels you don't need; You can create a helper function for that.
make a loop with if statement if there is what you are looking for or not
Here I use forEach() to loop through the data and get the boxes.
After that, I use filter() to get the object with the desired id. That's all.
const data = [
{
"boxes": [
{
"id": 2,
"content": {
"name": "ABC",
"details": "some details for abc"
}
}
]
},
{
"boxes": [
{
"id": 3,
"content": {
"name": "XYZ",
"details": "some details for xyz"
}
},
{
"id": 4,
"content": {
"name": "UVW",
"details": "some details for uvw"
}
}
]
},
{}
]
data.forEach(data => {
if (data.boxes){
let searchedData = data.boxes.filter(box => box.id == 3);
if (searchedData.length > 0){
console.log(searchedData[0].content);
}
}
});
I have a api response that return this :
{
"code": 0,
"message": "hierarchy list",
"payload": [
{
"id": 2,
"name": "nameParent",
"code": "WUcw",
"childsOfPayload": [
{
"id": 5,
"name": "NameChild1",
"code": "ozyW",
"status": "Active",
"childsofChildOfPayload": [
{
"id": 8,
"name": "NameChild2",
"code": "aitq",
"order": 30,
},
]}]}]}
I am trying to get the differents objects in each childs, ChildOfPayload and childOfChildOfpayload.
First I've returned the different name value of payload:
getAllPayloadName() {
this.userService.getName().subscribe(
data => {
this.values= data;
}
);
}
But what must I do to get the name of each child assosiated to the different parent value!
I mean in this case.
NameChild1
NameChild2
I've tried this:
manipulateDataa() {
this.values.subscribe(x => {
x.payload.foreach((y:any) => {
y.childs.foreach((z:any) => {
console.log( z.name)
})
})
})
}
then call it in getAllPayloadName, but still don't work. What could be wrong?
You could do something like this to get your desired output. Here you can read more about forEach loop which I have used.
data = {
"code": 0,
"message": "hierarchy list",
"payload": [
{
"id": 2,
"name": "nameParent",
"code": "WUcw",
"childsOfPayload": [
{
"id": 5,
"name": "NameChild1",
"code": "ozyW",
"status": "Active",
"childsofChildOfPayload": [
{
"id": 8,
"name": "NameChild2",
"code": "aitq",
"order": 30,
},
]}]}]}
names = []
function iterator (obj, namesArr){
Object.keys(obj).forEach(key => {
if(key === "name") {
namesArr.push(obj[key])
} else if(typeof obj[key] === "object") {
iterator(obj[key][0], names)
}
})
}
iterator(data.payload[0], names)
console.log(names)
if the api result structure is strongly type and will not change u can access the child payload name by this line
console.log(JSON.stringify(obj.payload[0].childsOfPayload[0].name));
console.log(JSON.stringify(obj.payload[0].childsOfPayload[0].childsofChildOfPayload[0].name));
I'm pulling two related objects from a web service - folders and emails. Folders have an ID and a parentfolder.ID property which indicates which parent folder a folder is nested beneath. Emails have a CategoryID which indicates which folder it is a child of.
I've successfully created a function to nest the emails within a flat folder structure:
{
"folders": [
{
"name": "my emails",
"type": "folder",
"additionalParameters": {
"id": "174661",
"type": "email",
"parentID": "0"
},
"children": [
{
"name": "Test1",
"type": "item",
"additionalParameters": {
"id": "27502",
"subject": "Test"
}
},
{
"name": "Hello",
"type": "item",
"additionalParameters": {
"id": "27917",
"subject": "Hi!"
}
}
]
},
{
"name": "Test",
"type": "folder",
"additionalParameters": {
"id": "175620",
"type": "email",
"parentID": "174661"
},
"children": [
{
"name": "Test2",
"type": "item",
"additionalParameters": {
"id": "27891",
"subject": "Test"
}
}
]
},
{
"name": "SubFolder1",
"type": "folder",
"additionalParameters": {
"id": "175621",
"type": "email",
"parentID": "175620"
},
"children": [
{
"name": "Test2",
"type": "item",
"additionalParameters": {
"id": "27892",
"subject": "Test"
}
},
{
"name": "Test3",
"type": "item",
"additionalParameters": {
"id": "27893",
"subject": "Test"
}
}
]
},
{
"name": "SubFolder2",
"type": "folder",
"additionalParameters": {
"id": "175622",
"type": "email",
"parentID": "175620"
},
"children": [
{
"name": "Test4",
"type": "item",
"additionalParameters": {
"id": "27894",
"subject": "Test"
}
}
]
}
]
}
Now I need to use recursion to loop through all of the folders and push them into the children array of their parent. Essentially resorting the tree to n levels. I can disregard any type=items because they are already nested appropriately. Just need to sort those whose types are folder.
Has anyone implemented a JSON recursion function to rebuild a JSON object with nesting?
Thanks for the help.
You can do this without recursion. I answered a similar question sometime back. I believe you could use the same approach (assuming you have no forward references):
var idToNodeMap = {}; //Keeps track of nodes using id as key, for fast lookup
var root = null; //Initially set our root to null
//loop over data
for(var i = 0; i < data.folders.length; i++) {
var folder = data.folders[i];
//each node will have children, so let's give it a "children" poperty
folder.children = [];
//add an entry for this node to the map so that any future children can
//lookup the parent
idToNodeMap[folder.additionalParameters.id] = folder;
//Does this node have a parent?
if(folder.additionalParamters.parentID === "0") {
//Doesn't look like it, so this node is the root of the tree
root = folder;
} else {
//This node has a parent, so let's look it up using the id
parentNode = idToNodeMap[folder.additionalParamters.parentID];
//Let's add the current node as a child of the parent node.
parentNode.children.push(folder);
}
}
Thanks to Vivin. Via his answer I found a link to an approach that ended up working. Here's the final code:
var arr = $this.folderArray;
// Define root
console.log("arr");
console.log(arr);
// Define tree
var tree = {
root: root
};
console.log('tree');
console.log(tree);
// Get parent of node (recursive)
var getParent = function (rootNode, rootId) {
console.log('rootnode');
console.log(rootNode);
console.log('rootId');
console.log(rootId);
if (rootNode.additionalParameters.id === rootId)
return rootNode;
for (var i = 0; i < rootNode.children.length; i++) {
var child = rootNode.children[i];
if (child.additionalParameters.id === rootId) return child;
if(child.children){
if (child.children.length > 0){
var childResult = getParent(child, rootId);
if (childResult != null) return childResult;
}
}
}
return null;
};
// Traverse data and build the tree
var buildTree = function(tree) {
for (var i = 0; i < arr.length; i++) {
var elem = arr[i];
if (elem.additionalParameters.parentID === "0")
continue;
//elem["children"] = [];
var rootId = elem.additionalParameters.parentID;
var parent = getParent(tree.root, rootId);
console.log("parent");
console.log(parent);
parent.children.push(elem);
// Debug info
// console.log("Elem: " + elem.name + " with parent_id: " + elem.parentAreaRef.id);
//console.log("Got parent with name: " + parent._id);
}
};
buildTree(tree);