Creating a Tree with javascript

I am trying to create a treeview with javascript. Basically, when a user clicks on a a chevron in the tree it will trigger SignalR to go and get the children, and once it has a list of children it sends them back to the client, one at a time, to be populated into the view. Sounds easy.

My problem is that when a child gets sent back, my code appends it to all children.

<ul class="treeview">
    <li id="1032">
        <i id="1032" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
        <a id="1032" href="#">Folder 1</a>
        <ul id="1032"></ul>
    </li>
    <li id="1018">
        <i id="1018" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
        <a id="1018" href="#">Folder 2</a>
        <ul id="1018"></ul>
    </li>
</ul>

When the page loads, it looks like this. When the i element gets clicked, my javascript triggers. Everything goes according to plan, except for the last method.

function addChild(parentID, childID, childName) {
            jQuery('<li id="' + childID + '"><i id="' +
            childID + '" class="tree-indicator glyphicon glyphicon-chevron-right"></i><a id="' +
            childID + '" href="#">' + childName + '</a><ul id="' + childID + '"></ul></li>').appendTo($("#" + parentID + " ul"));
        }

Folder 1 has 3 Children. What I am wanting it to come out like is this;

<ul class="treeview">
<li id="1032">
    <i id="1032" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
    <a id="1032" href="#">Folder 1</a>
    <ul id="1032">
        <li id="1057">
            <i id="1057" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="1057" href="#">Child 1</a>
            <ul id="1057"></ul>
        </li>
        <li id="4563">
            <i id="4563" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="4563" href="#">Child 2</a>
            <ul id="4563"></ul>
        </li>
        <li id="1534">
            <i id="1534" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="1534" href="#">Child 3</a>
            <ul id="1534"></ul>
        </li>
    </ul>
</li>
<li id="1018">
    <i id="1018" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
    <a id="1018" href="#">Folder 2</a>
    <ul id="1018"></ul>
</li>
</ul>

What is actually happening is this;

<ul class="treeview">
<li id="1032">
    <i id="1032" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
    <a id="1032" href="#">Folder 1</a>
    <ul id="1032">
        <li id="1057">
            <i id="1057" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="1057" href="#">Child 1</a>
            <ul id="1057">
                <li id="4563">
                    <i id="4563" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
                    <a id="4563" href="#">Child 2</a>
                    <ul id="4563">
                        <li id="1534">
                            <i id="1534" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
                            <a id="1534" href="#">Child 3</a>
                            <ul id="1534"></ul>
                        </li>
                    </ul>
                </li>
                <li id="1534">
                    <i id="1534" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
                    <a id="1534" href="#">Child 3</a>
                    <ul id="1534"></ul>
                </li>
            </ul>
        </li>
        <li id="4563">
            <i id="4563" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="4563" href="#">Child 2</a>
            <ul id="4563">
                <li id="1534">
                    <i id="1534" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
                    <a id="1534" href="#">Child 3</a>
                    <ul id="1534"></ul>
                </li>
            </ul>
        </li>
        <li id="1534">
            <i id="1534" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
            <a id="1534" href="#">Child 3</a>
            <ul id="1534"></ul>
        </li>
    </ul>
</li>
<li id="1018">
    <i id="1018" class="tree-indicator glyphicon glyphicon-chevron-right"></i>
    <a id="1018" href="#">Folder 2</a>
    <ul id="1018"></ul>
</li>
</ul>

This is going to be something small, I am pretty sure. I have just been looking at it for too long and my brain believes that everything is ok. This could also be due to the fact that jQuery is not strong with me.

Thanks in advance.

TO TEST The data is retrieved from a signalr class. For those that would like to test it out, I have made some buttons for you.

<button onclick="addChild(1032, 1057, 'Child 1')">Add Child 1</button> <button onclick="addChild(1032, 4563, 'Child 2')">Add Child 2</button> <button onclick="addChild(1032, 1534, 'Child 3')">Add Child 3</button>

Hope this helps a bit.

Answers 1

  • As K Scandrett noticed, the selector inside appendTo is too vague. As a result, it is appending the child node to all #parentID ul, that is all <ul> that are descendants of the #parentID node.

    To fix this, you could limit the selector to immediate descendants of the parent, like this: appendTo($('#' + parentID + ' > ul')). As long as the <ul> you are wanting is directly within the #parentID node, this will work.

    Another idea is to target the <ul> that has the #parentID. I noticed that you are sticking the same ID on all of the elements associated with each node, so appendTo($('ul#' + parentID)) ought to work as well.

    As for using duplicate element IDs all over the place, most browsers are hardy enough to tolerate it, but you could just use classes...


Related Articles