Find the parent of a javascript tree object array - javascript

Find the bellow parent child tree object I have created. I need to find the root parent of a given child id. For example child id - 242 root parent id is 238. There are similar questions have been asked and this is the one I found very similar to my question.
Convert parent-child array to tree
I have change the original code a bit But not working for child element. The issue is here. when it comes the recursive function with rootNode.children for loop will not execute since it does not loop through children. But if I change the for loop for (var i = 0; i < rootNode.length; i++) to for (var i = 0; i < rootNode.children.length; i++) then it break on first loop since does not have children. I'm sure with small code change this can make work.
var getParent = function (rootNode, rootId) {
if (rootNode.id === rootId)
return rootNode;
//for (var i = 0; i < rootNode.children.length; i++) -- original code line not working first time
for (var i = 0; i < rootNode.length; i++) {
var child = rootNode[i];
if (child.id === rootId)
return child;
if (typeof child.children !== 'undefined')
var childResult = getParent(child, rootId);
if (childResult != null) return childResult;
}
return null;
};
var mytree = [
{
"id": 245,
"parent": "0",
"title": "project1",
"children": [
{
"id": 246,
"parent": "245",
"title": "sub task 1"
}
]
},
{
"id": 238,
"parent": "0",
"title": "project2",
"children": [
{
"id": 240,
"parent": "238",
"title": "sub task 2"
},
{
"id": 242,
"parent": "238",
"title": "sub task 3",
"children" : [
{
"id": 241,
"parent": "242",
"title": "sub task 3.1"
}
]
}
]
},
{
"id": 173,
"parent": "0",
"title": "project3"
}
];
console.log(JSON.stringify(getParent(mytree, 238)['title']));
console.log(JSON.stringify(getParent(mytree, 241)));

You need to iterate the given root node, because this is an array, not an object.
function getParent(root, id) {
var node;
root.some(function (n) {
if (n.id === id) {
return node = n;
}
if (n.children) {
return node = getParent(n.children, id);
}
});
return node || null;
}
var mytree = [{ id: 245, parent: "0", title: "project1", children: [{ id: 246, parent: "245", title: "sub task 1" }] }, { id: 238, parent: "0", title: "project2", children: [{ id: 240, parent: "238", title: "sub task 2" }, { id: 242, parent: "238", title: "sub task 3", children: [{ id: 241, parent: "242", title: "sub task 3.1" }] }] }, { id: 173, parent: "0", title: "project3" }];
console.log(getParent(mytree, 238));
console.log(getParent(mytree, 241));
.as-console-wrapper { max-height: 100% !important; top: 0; }
More a classical attempt
function getParent(root, id) {
var i, node;
for (var i = 0; i < root.length; i++) {
node = root[i];
if (node.id === id || node.children && (node = getParent(node.children, id))) {
return node;
}
}
return null;
}
var mytree = [{ id: 245, parent: "0", title: "project1", children: [{ id: 246, parent: "245", title: "sub task 1" }] }, { id: 238, parent: "0", title: "project2", children: [{ id: 240, parent: "238", title: "sub task 2" }, { id: 242, parent: "238", title: "sub task 3", children: [{ id: 241, parent: "242", title: "sub task 3.1" }] }] }, { id: 173, parent: "0", title: "project3" }];
console.log(getParent(mytree, 238));
console.log(getParent(mytree, 241));
.as-console-wrapper { max-height: 100% !important; top: 0; }

I think my js tools can help you
https://github.com/wm123450405/linqjs
var mytree = [
{
"id": 245,
"parent": "0",
"title": "project1",
"children": [
{
"id": 246,
"parent": "245",
"title": "sub task 1"
}
]
},
{
"id": 238,
"parent": "0",
"title": "project2",
"children": [
{
"id": 240,
"parent": "238",
"title": "sub task 2"
},
{
"id": 242,
"parent": "238",
"title": "sub task 3",
"children" : [
{
"id": 241,
"parent": "242",
"title": "sub task 3.1"
}
]
}
]
},
{
"id": 173,
"parent": "0",
"title": "project3"
}
];
//node.asEnumerable get a Tree object
//isAncestorOf to predicate the root node is or not the ancestor node of parameter
console.log(mytree.find(node => node.asEnumerable(node => node.children, node => node.id).isAncestorOf(241)));
console.log(mytree.find(node => node.asEnumerable(node => node.children, node => node.id).isAncestorOf(242)).title);
<script src="https://wm123450405.github.io/linqjs/libs/linq-js.min.js"></script>

Related

Adding data to a nested JSON object with children based on an array - Javascript/REACT

Hello stackoverflow community! I've been creating my own fullstack application for a while now, on the NEXTjs framework. This is going pretty well!! Unfortunately, I got stuck on a JSON import object for a treeview component. The treeview component must be populated using a specific nested structure, along with which treeview item should be selected on an initial render.
I managed to get the correct JSON object from the database, using a sql recursive tree function.
const jsonObject =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
"children": []
},
{
"id": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"label": "sub category 1.2.2",
"children": []
}
]
}
]
}
The problem is that this object, with categories needs to be updated with a 'checked: "true"' or 'checked: "false"' key value pair based on the existence in the referenceSelectedCategories array. And I don't know how to do this; maintaining the structure and object as needed.
const desiredOutputJsonObject =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
** "checked": "false",**
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
** "checked": "true",**
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
** "checked": "false",**
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
** "checked": "false",**
"children": []
},
{
"id": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"label": "sub category 1.2.2",
** "checked": "true",**
"children": []
}
]
}
]
}
const referenceSelectedCategories =
[
{
"categoryId": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2"
},
{
"categoryId": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "b2e8681b-eec4-404d-8f87-c6314db42e30"
}
]
I've read several stackoverflow questions, also searched for examples, but can't get it to work. Could someone help me out here?
Some extra information:
Code language I'm using is REACT on NEXTjs framework;
Treeview component could have a dept of max 5 levels;
The structure of the JSON object doesn't change, it's exactly as presented above.
The "id" in the JSON object corresponds to the "categoryId" in the array.
Do you need more information? :) Just ask, I'll provide you with the extra details!
Kind Regards,
Chris
A straight forward solution with recursive method. Done a quick test, working fine. If any issues found, please point it out.
const parentObj =
[
{
"categoryId": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2"
},
{
"categoryId": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "b2e8681b-eec4-404d-8f87-c6314db42e30"
}
]
const existingId = parentObj.map((item)=> (item.Id))
const childobj =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
"children": []
},
{
"id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2",
"label": "sub category 1.2.2",
"children": []
}
]
}
]
}
const childObj = [childobj]
const updateData=(obj)=> {
if(existingId.includes(obj.id)) obj['checked'] = true; else obj['checked'] = false
}
const traverse=(childObj)=> {
for(const obj of childObj) {
updateData(obj);
if(obj.children.length > 0) traverse(obj.children);
}
}
traverse(childObj);
Here you can ty this logic :
let desiredOutputJsonObject = {
id: "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
label: "main category 1",
checked: false,
children: [
{
id: "12e544bc-91b1-4e5d-bdbc-2163a5618305",
label: "sub category 1.1",
checked: true,
children: [],
},
{
id: "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
label: "sub category 1.2",
checked: false,
children: [
{
id: "903a727f-d94d-44ff-b2f6-a985fd167343",
label: "sub category 1.2.1",
checked: false,
children: [],
},
{
id: "fb344480-8588-4ce3-9662-f8e89069e4b4",
label: "sub category 1.2.2",
checked: true,
children: [
{
id: "fb344480-8588-4ce3-9662-f8e89069e4b9",
label: "sub category 1.2.2",
checked: false,
children: [],
},
],
},
],
},
],
};
let referenceSelectedCategories = [
{
categoryId: "12e544bc-91b1-4e5d-bdbc-2163a5618305",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "f82b0f63-3f39-486c-9157-5c7683b8e3b2",
},
{
categoryId: "fb344480-8588-4ce3-9662-f8e89069e4b4",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "b2e8681b-eec4-404d-8f87-c6314db42e30",
},
{
categoryId:"fb344480-8588-4ce3-9662-f8e89069e4b9",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "b2e8681b-eec4-404d-8f87-c6314db42e30",
},
];
let stack = [desiredOutputJsonObject];
while (stack.length) {
let desiredOutput = stack.pop();
if (desiredOutput.children) {
desiredOutput.children.forEach((node) => {
//get node whose id == category id
let result = referenceSelectedCategories.find(
(obj) => obj.categoryId === node.id
);
// while traversing if we get referenceSelectedCategories.categoryId ==desiredOutputJsonObject.id
if (result) {
node.checked = true;
}
// for traverse purpose
if (node.children.length) {
stack.push(node);
}
});
}
}
console.log(desiredOutputJsonObject);

Form a nested tree from an array of objects in javascript

So there is array of objects of below format
let inputs = [
{
"id": "614344d9d9c21c0001e6af2e",
"groupName": "Unassigned",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f2e",
"groupName": "P1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f38",
"groupName": "K1",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f3e",
"groupName": "A2",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f40",
"groupName": "G1",
"parentGroup": "P2"
},
{
"id": "614447da152f69c3c1d52f46",
"groupName": "F1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f30",
"groupName": "P2",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f36",
"groupName": "C2",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f3c",
"groupName": "A1",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f34",
"groupName": "C1",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f32",
"groupName": "P3",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f3a",
"groupName": "K2",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f42",
"groupName": "GG1",
"parentGroup": "G1"
},
{
"id": "614447da152f69c3c1d52f44",
"groupName": "GGG1",
"parentGroup": "GG1"
}
]
i am trying to create a tree structure of format
{name:'p1',children:[{name:'c1':children:[]}]}
so i sorted all the elements of given array considering element with parentGroup as "null" to be at the top of the array.
let finalArr = [];
inputs.sort((a,b)=> (a.parentGroup === "null") ? -1 : 1);
And for each element of the inputs array, i was iterating below logic
inputs.forEach(ele => {
if(ele.parentGroup === "null"){
let child= {name:ele.groupName,children:[]};
finalArr.push(child);
}else{
finalArr.forEach(item => {
this.findNode(item,ele);
})
}
});
If the 'parentGroup' of element is "null", then create a leaf kind of obj and push the element to 'finalArr' array
Else, then iterate across all the elements of 'finalArr' over a recursion function
public findNode(ele, obj){
if(ele.children.length === 0){
if(ele.name === obj.parentGroup){
let child = {name:obj.groupName, children:[]};
ele.children.push(child);
}
}else{
let j = ele.children.length-1;
this.findNode(ele.children[j--],obj);
}
}
This recursion function will check the element has children or not, if no children, then compare the parentGroup of given obj, with name of element from 'FinalArr'.
if so ,push the current obj to the children of the element of finalArr.
else, that is, when children has more elements, the same recursion will be triggered until depth of the element is reached.
With this i tought i would make a tree structure with given inputs array, but when a parent has more children, of same level, this logic fails,
so the inputs array has 'c1' which is a child of 'p1', but nly the child 'c2' resides, not sure the what is that i missed.
You could take a standard algorithm for getting a tree with given data
const
getTree = (data, id, parent, root, fn = o => o) => {
var t = {};
data.forEach(o => ((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] = t[o[id]] || {}, fn(o))));
return t[root].children;
},
data = [{ id: "614344d9d9c21c0001e6af2e", groupName: "Unassigned", parentGroup: "null" }, { id: "614447da152f69c3c1d52f2e", groupName: "P1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f38", groupName: "K1", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f3e", groupName: "A2", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f40", groupName: "G1", parentGroup: "P2" }, { id: "614447da152f69c3c1d52f46", groupName: "F1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f30", groupName: "P2", parentGroup: "null" }, { id: "614447da152f69c3c1d52f36", groupName: "C2", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f3c", groupName: "A1", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f34", groupName: "C1", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f32", groupName: "P3", parentGroup: "null" }, { id: "614447da152f69c3c1d52f3a", groupName: "K2", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f42", groupName: "GG1", parentGroup: "G1" }, { id: "614447da152f69c3c1d52f44", groupName: "GGG1", parentGroup: "GG1" }],
tree = getTree(data, 'groupName', 'parentGroup', null, ({ groupName: name }) => ({ name }));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think the issue is how finalArr is used to generate the html elements.
When doing console.log(finalArr) it looks like the code block below. So it seems to me like the code you have to build the structure of finalArr is working fine.
// console.log(finalArr)
[
{ "name": "P3", "children": [] },
{
"name": "P2",
"children": [
{
"name": "G1",
"children": [
{ "name": "GG1", "children": [
{ "name": "GGG1", "children": [] }
]
}
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P1",
"children": [
{ "name": "C2", "children": [
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "Unassigned", "children": [] }
]
EDIT
As OP mentioned in the comment C1 was missing. I've introduced a root element that will have the finalArr as its children and changed the findNode to use a for loop instead of forEach. In this way we can also break when we find the node and not continue recursing.
As part of the initial sorting we will sort the inputs by parentGroup so we ensure that a childs parent is added in the tree structure before we try to find it with findNode.
I believe this produces the correct result:
inputs.sort((a, b) => (a.parentGroup === "null" ? -1 : 1));
// Sort by parentGroup
let root = inputs.pop();
let inputsDescending = [root];
let max = inputs.length * inputs.length;
let c = 0;
while (inputs.length > 0 && max > c) {
const child = inputs.pop();
const hasParentGroup = inputsDescending.find(
(parent) => parent.groupName === child.parentGroup
);
if (hasParentGroup || child.parentGroup === "null") {
inputsDescending.push(child);
} else {
inputs.unshift(child);
}
}
let rootEle = { name: "root", children: [] };
inputsDescending.forEach((obj) => {
if (obj.parentGroup === "null") {
let child = { name: obj.groupName, children: [] };
rootEle.children.push(child);
} else {
findNode(rootEle, obj);
}
});
function findNode(ele, obj) {
if (ele.name === obj.parentGroup) {
let child = { name: obj.groupName, children: [] };
ele.children.push(child);
return true;
} else {
const c = ele.children.length;
if (c > 0) {
for (let i = 0; c > i; i++) {
const found = findNode(ele.children[i], obj);
if (found) break;
}
}
}
}
const finalArr = rootEle.children;
Now finalArr looks like this:
[
{ "name": "Unassigned", "children": [] },
{
"name": "P1",
"children": [
{
"name": "C1",
"children": [
{ "name": "K1", "children": [] },
{ "name": "K2", "children": [] }
]
},
{
"name": "C2",
"children": [
{ "name": "A2", "children": [] },
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P2",
"children": [
{ "name": "G1", "children": [
{ "name": "GG1", "children": [] }
]
}
]
},
{ "name": "P3", "children": [] }
]

Parsing categories tree into HTML select tag

I have this categories tree input :
"categories": [
{
"text": "Upstate",
"id": 3,
"category_parent_id": 0,
"children": []
},
{
"text": "North",
"id": 2,
"category_parent_id": 0,
"children": [
{
"text": "Child N 1",
"id": 5,
"category_parent_id": 2,
"children": [
{
"text": "Another Child 1",
"id": 11,
"category_parent_id": 5,
"children": []
},
{
"text": "Another Child 2",
"id": 10,
"category_parent_id": 5,
"children": []
}
]
},
{
"text": "Activity",
"id": 4,
"category_parent_id": 2,
"children": []
}
]
},
{
"text": "Health",
"id": 1,
"category_parent_id": 0,
"children": [
{
"text": "Good Health",
"id": 9,
"category_parent_id": 1,
"children": []
},
{
"text": "Bad Health",
"id": 8,
"category_parent_id": 1,
"children": []
}
]
}
]
So, now I want to populate my select box like this :
Upstate
North
-Child N 1
--Another Child 1
--Another Child 2
-Activity
Health
-Good Health
-Bad Health
So, how can I parse through the input tree and populate the select box with these values? Any algorithm or recursive function approach I can use to achieve this ?
make a recursive function
flatCategories(data: any[], children: any[], index: number) {
data=data||[];
children.forEach(x => {
data.push({ id: x.id, text: '-'.repeat(index) + x.text });
if (x.children && x.children.length)
this.flatCategories(data, x.children, index + 1)
})
return data
}
You can use like
let dataFlat=this.flatCategories([], this.data.categories, 0);
console.log(this.dataflat.map(x => x.text))
If you want to create a recursive component it's easy (but in case of select not work)
#Component({
selector: 'item-line',
template: `
<div *ngFor="let item of children" [style.margin-left]="index+'rem'">
{{item.text}}
<item-line *ngIf="item.children" [children]="item.children" [index]="index+1">
</item-line>
</div>
`,
})
export class HelloComponent {
#Input() children:any[]
#Input() index:number=0;
}
You can see in stackblitz

How to create tree view in js

I have a dummy data like this
i need to create a tree like this
CEO
A
A1
A2
My dummy look like this
let d = [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
},
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
];
I have tried somthing like this
var newObj = {tree:d.filter(d=>!d.parent)};
var tree = newObj.tree;
for(let k in tree){
for(let i = 0 ; i < tree.length ; i++){
newObj.tree[i]['child']=this.returnChildNode(tree[i].id,d);
}
}
console.log(newObj);
private returnChildNode(parentId ,arr){
if(arr.filter(d=>d.parent===parentId).length < 1) return null ;
else return arr.filter(d=>d.parent===parentId);
}
Output getting is
{
"tree": [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428",
"child": [
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
]
}
]
}
How to complete it by recursion for deep going in generic way
Here's a recursive option using reduce
let d = [{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
}, {
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
}, {
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
}, {
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}]
const rec = (parent, arr) => {
const ref = parent ? parent.id : null
const children = arr.reduce((ac, x) => {
if (x.parent === ref)
ac.push(rec(x, arr))
return ac
}, [])
if (parent)
parent.children = children
return (
parent ?
parent :
children[0]
)
}
const res = rec(null, d)
console.log(res)
You can try this :
var data = [
{
name: "CEO",
parent: null,
id: "0"
},
{
name: "A",
parent: "0",
id: "1"
},
{
name: "A1",
parent: "1",
id: "2"
},
{
name: "A2",
parent: "1",
id: "3"
},
{
name: "A3",
parent: "1",
id: "4"
},
{
name: "b",
parent: "0",
id: "5"
},
{
name: "A1",
parent: "5",
id: "6"
},
{
name: "A2",
parent: "5",
id: "7"
},
{
name: "A3",
parent: "5",
id: "8"
},
];
// data is an array in the above format
function toTree(data) {
var childrenById = {}; // of the form id: [child-ids]
var nodes = {}; // of the form id: {name: children: }
var i, row;
// first pass: build child arrays and initial node array
for (i=0; i<data.length; i++) {
row = data[i];
nodes[row.id] = {name: row.name, children: []};
if (row.parent == null) {
// assume -1 is used to mark the root's "parent"
root = row.id;
} else if (childrenById[row.parent] === undefined) {
childrenById[row.parent] = [row.id];
} else {
childrenById[row.parent].push(row.id);
}
}
// second pass: build tree, using the awesome power of recursion!
function expand(id) {
if (childrenById[id] !== undefined) {
for (var i=0; i < childrenById[id].length; i ++) {
var childId = childrenById[id][i];
nodes[id].children.push(expand(childId));
}
}
return nodes[id];
}
return expand(root);
}
console.log(JSON.stringify(toTree(data)));

Get all children from parent child JSON data

I have parent-child JSON data and I want get all children (nested children) from selected parent.
For example, I have JSON data :
[{
"id": 1,
"parent": 0,
"name": "Parent"
}, {
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
And I have function findAllChildren(1), where "1" is "parent" and then result of function should be :
[{
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
And in other case, if i call findAllChildren(2), result of the function should like below :
[{
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}]
What is the proper way to create function to solve that case? Thank you.
You can just iterate over the original data and look for items that has the specified id as parent_id. If found, do the same recursively with the element's id.
Check it out here: https://jsfiddle.net/6ydog1tj/2/
function findAllChildren (id, results, depth) {
for (d in data) {
if (data[d].parent == id) {
data[d].depth = depth
results.push(data[d])
findAllChildren(data[d].id, results, depth + 1)
}
}
}
var results = []
findAllChildren(1, results, 0)
$('body').append(results.map(function (element) { return Array(element.depth + 1).join(' -> ') + element.name + '<br>' }))
console.log(results)
prints out
Child 1
-> Grand Child 1
-> Grand Child 2
Child 2
I suggest to iterate all data and build a tree like object with properties to start the search with all given id.
Then the object is walked and the children iterated for the result.
function getDescendant(id) {
var result = [];
Array.isArray(object[id].children) && object[id].children.forEach(function iter(a) {
result.push({ id: a.id, parent: a.parent, name: a.name });
Array.isArray(a.children) && a.children.forEach(iter);
});
return result;
}
var data = [{ id: 1, parent: 0, name: "Parent" }, { id: 2, parent: 1, name: "Child 1" }, { id: 3, parent: 2, name: "Grand Child 1" }, { id: 4, parent: 2, name: "Grand Child 2" }, { id: 5, parent: 1, name: "Child 2" }],
object = function (data, root) {
var o = {};
data.forEach(function (a) {
a.children = o[a.id] && o[a.id].children;
o[a.id] = a;
o[a.parent] = o[a.parent] || {};
o[a.parent].children = o[a.parent].children || [];
o[a.parent].children.push(a);
});
return o;
}(data, 0);
console.log(getDescendant(1));
console.log(getDescendant(2));
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.filter to remove items from an array that do not match a predicate condition.
filter will loop over an array and run a function for each iteration. it the return value is true the item will be in the returned array.
The parentId function passed into filter is curried. it will lock in the parent id you are searching for in the scope and return the function that filter will run.
const data = [{
"id": 1,
"parent": 0,
"name": "Parent"
}, {
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
function parentId(id) {
return function(item) {
return item.parent === id
}
}
console.log(
data.filter(parentId(2))
)

Categories