I have an requirement to create a tree structure menu from a . separated string array.
My out put should be like following
A
A1
A2
A3
B1
B2
B
B1
B2
B3
B4
C
C1
C2
C4
I am trying to implement that with the following script
<script>
function fnAppend(param) {
var cWin=window.open("","Categories","width=600,height=800,scrollbars=yes");
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [],
levels = [tree],
last = [];
array.forEach(s => {
var temp = s.split('.');
temp.forEach((name, i) => {
if (last[i] === name) return;
levels[i].push({ name, children: levels[i + 1] = [] });
});
last = temp;
});
function traverse(arr) {
for (const branch of arr) {
console.log('Mother:', branch.name);
var ul=document.createElement('ul');
var li=document.createElement('li');
li.innerHTML="<a href=''>"+branch.name+"</a>";
ul.appendChild(li);
if (Array.isArray(branch.children) && branch.children.length > 0) {
console.log('Children:', branch.children.map(i => i.name).join(', '));
traverse(branch.children);
}
}
var list = document.createElement('div');
list.appendChild(ul);
try {
cWin.document.body.appendChild(list);
} catch (err) {
if (list.outerHTML) {
cWin.document.body.innerHTML = list.outerHTML;
} else {
console.log(err.name);
}
}
}
traverse(tree);
}
</script>
</head>
<body>
<ul id="mylist">
</ul>
<input type="button" value="Append child" onclick="fnAppend('test')" />
</body>
Using above script I am getting the following output
A3
B2
B1
C2
C1
B4
B3
B1
C4
Please help me to format the output. Many thanks in advance.
Regards, Pankaj
1 Answer 1
You could create tree and build a nested list with items.
function buildList(tree, target) {
var ul = document.createElement('ul');
tree.forEach(node => {
var li = document.createElement('li');
li.appendChild(document.createTextNode(node.name));
node.children.length && buildList(node.children, li);
ul.appendChild(li);
});
target.appendChild(ul);
}
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [];
array.forEach(s => s.split('.').reduce((t, name) => {
var temp = t.find(o => o.name === name);
if (!temp) {
t.push(temp = { name, children: [] });
}
return temp.children;
}, tree));
console.log(tree);
buildList(tree, document.body);
A different approach wich works only if pop ups are allowed.
function open() {
var cWin = window.open("", "Categories", "width=600,height=800,scrollbars=yes");
cWin.document.write(buildList(tree).outerHTML);
}
function buildList(tree) {
if (!tree.length) return;
var ul = document.createElement('ul');
tree.forEach(node => {
var li = document.createElement('li'),
children = buildList(node.children);
li.appendChild(document.createTextNode(node.name));
if (children) li.appendChild(children);
ul.appendChild(li);
});
return ul;
}
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [];
array.forEach(s => s.split('.').reduce((t, name) => {
var temp = t.find(o => o.name === name);
if (!temp) {
t.push(temp = { name, children: [] });
}
return temp.children;
}, tree));
console.log(tree);
<button onclick="open()">popup</button>
answered Mar 11, 2019 at 8:23
Nina Scholz
388k26 gold badges367 silver badges417 bronze badges
Sign up to request clarification or add additional context in comments.
16 Comments
Pankaj Karmakar
Hi Nina, Thank you very much for your response.It will working fine but I have another question, if I need to open the tree in a new window, how to do that?
Nina Scholz
@PankajKarmakar, please try the last one outside of stack snippets.
Pankaj Karmakar
Its working but if you check my code there I have to open the new window with menu once I have click on a button.
Pankaj Karmakar
Hi Nina,Is there any way to append a class to next li of each parant and also need to add <a> to all the end child li of every parent.
Nina Scholz
you could add this in the
forEach callback. |
lang-js