How to create dynamic nested accordion in React - javascript

How i can create an accordion like this
-parent
-subparent1
-subparent2
...
-subparentN
- child
Here is my data.
//parents
{id: 1, name: "", parent_id: null}
{id: 2, name: "", parent_id: null }
{id: 3, name: "", parent_id: null }
{id: 4, name: "", parent_id: null}
//children
{id: 5, name: "", parent_id: 1}
{id: 6, name: "", parent_id: 1}
{id: 7, name: "", parent_id: 5}
{id: 8, name: "", parent_id: 5}
{id: 9, name: "", parent_id: 6}
{id: 10, name: "", parent_id: 6}
{id: 11, name: "", parent_id: 6}
{id: 12, name: "", parent_id: 6}
{id: 13,name: "", parent_id: 6}
{id: 14, name: "", parent_id: 6}
Basically the ones who have parent_id:null are parents, and when I click on them I want their potential children to be displayed if they have any, now this isn't that hard, but what I can't understand is how to display subparent's children

You can loop over the list of all your items and add each sub item to their parent. Afterwards you just have to loop over all the items in the array and create their respective html.
const items = [
//parents
{id: 1, name: "1", parent_id: null},
{id: 2, name: "2", parent_id: null },
{id: 3, name: "3", parent_id: null },
{id: 4, name: "4", parent_id: null},
//children
{id: 5, name: "5", parent_id: 1},
{id: 6, name: "6", parent_id: 1},
{id: 7, name: "7", parent_id: 5},
{id: 8, name: "8", parent_id: 5},
{id: 9, name: "9", parent_id: 6},
{id: 10, name: "10", parent_id: 6},
{id: 11, name: "11", parent_id: 6},
{id: 12, name: "12", parent_id: 6},
{id: 13,name: "13", parent_id: 6},
{id: 14, name: "14", parent_id: 6},
];
for(const item of items) {
// Find the parent object
const parent = items.find(({ id }) => id === item.parent_id);
// If the parent is found add the object to its children array
if(parent) {
parent.children = parent.children ? [...parent.children, item] : [item]
}
};
// Only keep root elements (parents) in the main array
const list = items.filter(({ parent_id }) => !parent_id);
// console.log(list);
// Show tree (vanillaJS, no REACT)
for(const item of list) {
// Create a new branch for each item
const ul = createBranch(item);
// Append branch to the document
document.body.appendChild(ul);
}
function createBranch(item) {
// Create ul item for each branch
const ul = document.createElement("ul");
// Add current item as li to the branch
const li = document.createElement("li");
li.textContent = item.name;
ul.appendChild(li);
// Check if there are children
if(item.children) {
// Create a new branch for each child
for(const child of item.children) {
const subUl = createBranch(child);
// Append child branch to current branch
ul.appendChild(subUl);
}
}
return ul;
}
ul {
margin: 0;
padding-left: 2rem;
}

I think your data structure should be a nested object similarly to how you see your menu working, i.e.
[
{id: 1, name:"", children: [
{id: 5, name: "", children: []},
{id: 6, name: "", children: [
{id: 7, name: "", children: []},
{id: 8, name: "", children: []},
]},
]},
{id: 2, name:"", children:[]}
]
Then you would need a function to output each item:
const returnMenuItem = (item, i) =>{
let menuItem;
if (item.children.length===0) {
menuItem = <div key={i}>{item.label}</div>;
}
else {
let menuItemChildren = item.children.map((item,i)=>{
let menuItem = returnMenuItem(item,i);
return menuItem;
});
menuItem = <div key={i}>
<div>{item.label}</div>
<div>
{menuItemChildren}
</div>
</div>;
}
return menuItem;
}
And you would invoke this function by going through your items:
let menuItems = data.map((item,i)=>{
let menuItem = returnMenuItem(item,i);
return menuItem;
});
A complete component would look something like the following:
import React, { useState, useEffect } from "react";
import { UncontrolledCollapse } from "reactstrap";
const Menu = (props) => {
const [loading, setLoading] = useState(true);
const [items, setItems] = useState([]);
useEffect(() => {
const menuData = [
{
id: 1,
name: "test 1",
children: [
{ id: 5, name: "test 5", children: [] },
{
id: 6,
name: "test 6",
children: [
{ id: 7, name: "test 7", children: [] },
{ id: 8, name: "test 8", children: [] }
]
}
]
},
{ id: 2, name: "test 2", children: [] }
];
const returnMenuItem = (item, i) => {
let menuItem;
if (item.children.length === 0) {
menuItem = (
<div className="item" key={i}>
{item.name}
</div>
);
} else {
let menuItemChildren = item.children.map((item, i) => {
let menuItem = returnMenuItem(item, i);
return menuItem;
});
menuItem = (
<div key={i} className="item">
<div className="toggler" id={`toggle-menu-item-${item.id}`}>
{item.name}
</div>
<UncontrolledCollapse
className="children"
toggler={`#toggle-menu-item-${item.id}`}
>
{menuItemChildren}
</UncontrolledCollapse>
</div>
);
}
return menuItem;
};
const load = async () => {
setLoading(false);
let menuItems = menuData.map((item, i) => {
let menuItem = returnMenuItem(item, i);
return menuItem;
});
setItems(menuItems);
};
if (loading) {
load();
}
}, [loading]);
return <div className="items">{items}</div>;
};
export default Menu;
And a minimum css:
.item {
display: block;
}
.item > .children {
padding: 0 0 0 40px;
}
.item > .toggler {
display: inline-block;
}
.item::before {
content: "-";
padding: 0 5px 0 0;
}
You can find a working code sandbox here sandbox

I think that your data structure has a flaw. Beside child to parent relation, you should keep track of parent to child relationship. Now you will be able to easily iterate through the data and render sub parent's children.
{id: 1, parent_id: null, children: [
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [
{id: 4, parent_id: 3, children: []}
]}
]}
If you need to keep all objects inline, you can structure your data like:
{id: 1, parent_id: null, children: [2, 3]}
{id: 2, parent_id: 1, children: []},
{id: 3, parent_id: 1, children: [4]},
{id: 4, parent_id: 3, children: []}

Related

Create a hierarchy of arrays from a flat array

Consider I have an array like this
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
How do I create a hierarchy of just one object like this
{
id: 1,
name: "A",
parent: null,
children: [
{
id: 11,
name: "AA",
parent: 1,
children: [
{id: 111, name: "AAA", parent: 11}],
},
{id: 2, name: "B", parent: 1, children: []},
{
id: 4,
name: "C",
parent: 1,
children: [{id: 41, name: "CC", parent: 4, children: []}],
},
],
}
The id is actually not a number in my actual app. It's a random string BTW.
I could do it recursively by drilling through the children array but it is not the most effective way. Can somebody help please?
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
const hierarchy = (arr) => {
const map = {};
let root;
for (const ele of arr) {
map[ele.id] = ele;
ele.children = [];
}
for (const ele of arr) {
if (map[ele.parent] != undefined)
map[ele.parent].children.push(ele);
else
root = ele;
}
return root;
}
console.log(hierarchy(ar));
First step is to map the items by the id so you have an easy look up so you are not looping over the array multiple times. After that you just need to loop over and add a children array to the parent and add the reference.
const ar = [
{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1},
];
// make a look up by the id
const mapped = ar.reduce((acc, item) => {
acc[item.id] = item;
return acc;
}, {});
// loop over
const result = ar.reduce((acc, item) => {
// if there there is no parent, we know it is the first so return it
const parentId = item.parent;
if (!parentId) return item;
// if we have a parent, see if we found this yet, if not add the array
mapped[parentId].children = mapped[parentId].children || [];
// set the item as a child
mapped[parentId].children.push(item);
return acc;
}, null);
console.log(result)
You can iterate through the array and push the elem to the right place each time.
To get the root, you can then retrieve the element without parent.
const arr = [{id: 1, name: "A", parent: null},
{id: 2, name: "B", parent: 1},
{id: 11, name: "AA", parent: 1},
{id: 12, name: "AB", parent: 1},
{id: 111, name: "AAA", parent: 11},
{id: 41, name: "CC", parent: 4},
{id: 4, name: "C", parent: 1}]
arr.forEach(elem => elem.children = [])
arr.forEach(elem => {
if(elem.parent){
const parent = arr.find(x => x.id === elem.parent)
if(parent)parent.children.push(elem)
}
})
console.log(arr.find(x => !x.parent))
Note : If you want to optimize a little more, you can add the children array in the second forEach

array grouping conversion key start_section to end_section

Let's say I have below array :
[{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
]
I want this :
[{
id: 1,
name: "header"
}, {
id: 2,
name: "section",
child: [{
{
id: 3,
name: "input"
},
{
id: 5,
name: "image"
},
}],
}, {
id: 7,
name: "header"
}, {
id: 8,
name: "section",
child: [{
{
id: 9,
name: "input"
},
{
id: 10,
name: "date"
},
}]
}]
if I find start_section and end_section then it will form a new object , How do I change the array by grouping by the key specified in the example above in javascript?
If I get it right, you want something like this? It's simple approach with for loop and some flags:
const arr = [{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
];
// Set final array
let finalArray = [];
// Set sub object for groups (Childs)
let subObj = {};
// Flag for sub section stuff
let inSubSection = false;
// Loop array
for(let i = 0; i < arr.length; i++) {
if(arr[i].name === "end_section") {
// If we have end_section
// Set flag off
inSubSection = false;
// Push sub object to final array
finalArray.push(subObj);
} else if(arr[i].name === "start_section") {
// If we get start_section
// Set flag on
inSubSection = true;
// Set new sub object, set childs array in it
subObj = {
id: arr[i].id,
name: "section",
child: []
};
} else if(inSubSection) {
// If we have active flag (true)
// Push child to section array
subObj.child.push({
id: arr[i].id,
name: arr[i].name
});
} else {
// Everything else push straight to final array
finalArray.push(arr[i]);
}
}
// Log
console.log(finalArray);
you can Array.reduce function
let array = [{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
]
let outPut = array.reduce( (acc, cur, i, arr) => {
if (cur.name == "start_section") {
//find the end element
let endIndex = arr.slice(i).findIndex( e => e.name == "end_section") + i ;
//splice the child elements from base array
let child = arr.splice(i + 1, endIndex - 1 );
//remove last element that has "end_section"
child.splice(-1);
//append child
cur.child = child;
//sert the name as "section"
cur.name = "section";
}
//add to accumulator
acc.push(cur);
return acc;
}, []);
console.log(outPut);

Link child and parent on the basic of depth level

I have all my parent children in a single array data.What i want is to add a new attribute (level) on each objects.
Given i have data as
var data = [
{
id: 1,
parent_id: 0,
name: "Child1",
},
{
id: 4,
parent_id: 1,
name: "Child11",
},
{
id: 5,
parent_id: 4,
name: "Child111",
},
{
id: 11,
parent_id: 4,
name: "Child112"
},
{
id: 13,
parent_id: 11,
name: "Child1121",
},
{
id: 21,
parent_id: 11,
name: "Child1122"
},
{
id: 22,
parent_id: 11,
name: "Child1123"
},
{
id: 24,
parent_id: 1,
name: 'Child12'
}
]
I want a child-parent relationship based on the parent_id of the children and assign a new attribute in each object of the array as level which represents the depth level of the children based on its parent.My Expected result is :
var data = [
{
id: 1,
parent_id: 0, <-------represents root
name: "Child1",
level:0 <--------level based on its parent_id
},
{
id: 4,
parent_id: 1
name: "Child11",
level:1
},
{
id: 5,
parent_id: 4,
name: "Child111",
level:2
},
{
id: 11,
parent_id: 4,
name: "Child112",
level:2
},
{
id: 13,
parent_id: 11,
name: "Child1121",
level:3
},
{
id: 21,
parent_id: 11,
name: "Child1122",
level:3
},
{
id: 22,
parent_id: 11,
name: "Child1123",
level:3
},
{
id: 24,
parent_id: 1,
name: 'Child12',
level:1
}
]
My Code
function buildTree(elements, parent_id, level = 0) {
elements.forEach(element => {
if (element['parent_id'] == parent_id) {
console.log('parent_id', parent_id);
// elements.filter(item=>item!==element);
element['level'] = level;
}
else{
buildTree(elements,parent_id,level+1);
}
})
return elements;
}
For sorted data, you could take an object for the level count and map a new data set.
var data = [{ id: 1, parent_id: 0, name: "Child1" }, { id: 4, parent_id: 1, name: "Child11" }, { id: 5, parent_id: 4, name: "Child111" }, { id: 11, parent_id: 4, name: "Child112" }, { id: 13, parent_id: 11, name: "Child1121" }, { id: 21, parent_id: 11, name: "Child1122" }, { id: 22, parent_id: 11, name: "Child1123" }, { id: 24, parent_id: 1, name: 'Child12' }],
levels = {},
result = data.map(o => ({
...o,
level: levels[o.id] = o.parent_id in levels
? levels[o.parent_id] + 1
: 0
}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this
let parentLevel = []
data.map(parent => {
const { parent_id } = parent
if (!parentLevel.includes(parent_id)) {
parentLevel.push(parent_id);
}
})
const updatedData = data.map(parent => {
const { parent_id } = parent
parent.level = parentLevel.indexOf(parent_id)
return parent
})
console.log(updatedData);
The result is
(8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {id: 1, parent_id: 0, name: "Child1", level: 0}
1: {id: 4, parent_id: 1, name: "Child11", level: 1}
2: {id: 5, parent_id: 4, name: "Child111", level: 2}
3: {id: 11, parent_id: 4, name: "Child112", level: 2}
4: {id: 13, parent_id: 11, name: "Child1121", level: 3}
5: {id: 21, parent_id: 11, name: "Child1122", level: 3}
6: {id: 22, parent_id: 11, name: "Child1123", level: 3}
7: {id: 24, parent_id: 1, name: "Child12", level: 1}
If data is not sorted in a way that the parent is guaranteed to come before any of its children, then use a Map keyed by id values, which also gives better efficiency (no linear lookup in every iteration):
let data = [{ id: 1, parent_id: 0, name: "Child1" }, { id: 4, parent_id: 1, name: "Child11" }, { id: 5, parent_id: 4, name: "Child111" }, { id: 11, parent_id: 4, name: "Child112" }, { id: 13, parent_id: 11, name: "Child1121" }, { id: 21, parent_id: 11, name: "Child1122" }, { id: 22, parent_id: 11, name: "Child1123" }, { id: 24, parent_id: 1, name: 'Child12' }];
// optional step if you don't want to mutate the original objects in the array:
data = data.map(o => ({...o}));
const map = new Map(data.map(o => [o.id, o])).set(0, { level: -1 });
const setLevel = o => "level" in o ? o.level : (o.level = 1 + setLevel(map.get(o.parent_id)));
data.forEach(setLevel);
console.log(data);
You can omit the optional assignment when you are OK with adding the level property to the existing objects. But if you want the original data objects to remain untouched, and have newly created objects for storing the level property, then keep that line in.

Efficient way of writing child of parents in javascript

var array = [
{id: 1, name: "Father", parent_id: null},
{id: 2, name: "Child", parent_id: 1},
{id: 3, name: "Child", parent_id: 1},
{id: 4, name: "ChildChild", parent_id: 2},
{id: 5, name: "ChildChildChild", parent_id: 4}
]
for(var i in array){
if(array[i].parent_id == null){
console.log(array[i].name);
} else {
for(var j in array){
if(array[i].parent_id == array[j].id && array[j].parent_id == null){
console.log(">" + array[i].name);
for(var x in array){
if(array[i].id == array[x].parent_id){
console.log(">>" + array[x].name);
}
}
}
}
}
}
Output:
Father
>Child
>>ChildChild
>Child
I have this array which has id, name and parent_id. Right now it is fixed but it could have multiple arrays and can be nested for n amount of times.
What I am doing here is iterating through each array and trying to find which are the parents and which one is the child.
I want to know if there is a more efficient way to write this code. For instance, I added a fifth id but that would require another for loop and so on. The output would be the same just a printed out tree.
You can use a Map to key your nodes by id, and then use recursion to traverse them in depth first order:
var array = [{id: 1, name: "Father", parent_id: null},{id: 2, name: "Child", parent_id: 1},{id: 3, name: "Child", parent_id: 1},{id: 4, name: "ChildChild", parent_id: 2},{id: 5, name: "ChildChildChild", parent_id: 4}];
let map = new Map(array.map(({id}) => [id, []])).set(null, []);
array.forEach(node => map.get(node.parent_id).push(node));
function dfs(nodes, indent="") {
for (let node of nodes) {
console.log(indent + node.name);
dfs(map.get(node.id), indent+">");
}
}
dfs(map.get(null));
You could create a tree and then make the output.
const
print = ({ name, children = [] }) => {
console.log(name)
children.forEach(print);
},
array = [{ id: 1, name: "Father", parent_id: null }, { id: 2, name: "Child", parent_id: 1 }, { id: 3, name: "Child", parent_id: 1 }, { id: 4, name: "ChildChild", parent_id: 2 }, { id: 5, name: "ChildChildChild", parent_id: 4 }],
tree = function (data, root) {
var t = {};
data.forEach(o => {
Object.assign(t[o.id] = t[o.id] || {}, o);
t[o.parent_id] = t[o.parent_id] || {};
t[o.parent_id].children = t[o.parent_id].children || [];
t[o.parent_id].children.push(t[o.id]);
});
return t[root].children;
}(array, null);
tree.forEach(print);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to build a tree from a flat list in FP JS

I'm learning Functional Javascript and encounter into a problem.
I have this flat object:
const data = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
]
I desire to convert it to this hierarchical object, using only pure functions, no fors, ifs and other "imperative style statements".
Result should be:
[{
id: 1,
name: "Folder1",
parentId: null,
children = [{
id: 3,
name: "Folder3",
parentId: 1,
children = [{
id: 5,
name: "Folder5",
parentId: 3
},
{
id: 6,
name: "Folder6",
parentId: 3
}
]
}]
},
{
id: 2,
name: "Folder2",
parentId: null,
children = [{
id: 4,
name: "Folder4",
parentId: 2
}]
}
]
Any Ideas?
This is a proposal without if, but with Array#reduce and Map. It needs a sorted array.
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }],
tree = data
.reduce(
(m, a) => (
m
.get(a.parentId)
.push(Object.assign({}, a, { children: m.set(a.id, []).get(a.id) })),
m
),
new Map([[null, []]])
)
.get(null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or the same as above using ES2015 destructuring assignment. It needs a sorted array and also depends on the input data having only id, name and parentId keys.
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }],
tree = data
.reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Of course this should probably be written as a reusable function ...
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }];
// pure, reusable function
var buildTree = (data) =>
data.reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(buildTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Lastly, if the data is arriving in an unsorted order, we could handle sorting with a custom comparator
// unsorted data example
var data = [{ id: 6, name: "Folder6", parentId: 3 }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 1, name: "Folder1", parentId: null }];
// immutable sort
var sort = (f,xs) => [...xs.sort(f)];
// custom tree comparator
var treeComparator = (x,y) =>
x.parentId - y.parentId || x.id - y.id;
// sort data, then reduce
var buildTree = (data) =>
sort(treeComparator, data).reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(buildTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with recursive function but you need to loop array with reduce and use if statements.
const arr = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
]
function buildTree(data, pId) {
return data.reduce(function(r, e) {
var e = Object.assign({}, e);
if (e.parentId == pId) {
var children = buildTree(data, e.id)
if (children.length) e.children = children
r.push(e)
}
return r;
}, [])
}
console.log(buildTree(arr, null))
const data = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
];
function trampoline ( f ) {
while ( f && f instanceof Function ) { f = f ( ); }
return f;
}
function buildTree ( data, copy, top = [] ) {
function recur ( data, copy, top ) {
copy = copy || data.concat ( [] );
let current = copy.shift ( );
current ? doWork ( ) : null;
function doWork ( ) {
top = top.concat ( ( ! current.parentId ? current : [] ) );
current.children = copy.filter ( x => { return current.id === x.parentId } );
}
return ( current ? recur.bind ( null, data, copy, top ) : top );
}
return trampoline ( recur.bind ( null, data, copy, top ) );
}
data.map ( x => { x [ 'children' ] = [ ]; return x; } );
console.log ( buildTree ( data ) );

Categories