2

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

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>

Sign up to request clarification or add additional context in comments.

16 Comments

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?
@PankajKarmakar, please try the last one outside of stack snippets.
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.
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.
you could add this in the forEach callback.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.