1

I've seen several questions about converting an array/object into a nested list, but I've found only one relevant question to my issue. I've tried a few ways of accessing children of an element, but it only breaks my code further.

I have a nested, unordered list.

<div id="sortableSitemap">
    <ul class="sortable ui-sortable">
        <li id="world_news_now"><div>World</div>
            <ul>
                <li id="the_news"><div>The News</div></li>
            </ul>
        </li>
        <li id="sports_news_cool"><div>Sports</div></li>
    </ul>
</div>

At the moment, it contains 3 items and appears like so:

-World
    --The News
-Sports

There can be any number of nodes with varying depths. I'm trying to store the list into an array with some additional information.

Each node gets a numeric, sequential ID (first node is 1, second is 2) based on the order it appears, regardless of depth (i.e. World = 1, The News = 2, Sports = 3). I also want to store the ID of a node's parent (root is 0). So, the parent IDs would be: World = 0, The News = 1, Sports = 0.

The code below seems to work except when the list is like the one above. In that case, it assigns The News = 3 and its parent = 2 (Sports). For some reason, iterating through the items (children) ends up getting to the <ul> last, even if it's directly after an open <li>.

All but one jQuery solution I found ignores depth, and even then, I need the actual parent node's ID (which I currently keep in a stack based on whether I've gone down a level).

Why is this happening, and how can I modify my code to go through the list recursively?

var count = 0;
var pages = [];
var parentStack = [];

            function createNewLevel(items) {
                var length = items.length;
                for (var i = 0; i < length; i++) {

                    if (items[i].tagName == 'UL') {

                        parentStack.push(count);
                        createNewLevel($(items[i]).children().get());
                        parentStack.pop();

                    } else {
                        ++count;
                        pages.push({
                            pId: parentStack[parentStack.length - 1],
                            urlStr: $(items[i]).attr('id'), myId: count
                        });
                    }
                }

            }

            createNewLevel($('#sortableSitemap ul').get());

            console.log(pages);

Update: Here's a jsFiddle to show how the code does not work ("The News" should have "World" as its parent node).

2
  • Can I ask why you want to do this? Converting a html list to object? Commented Aug 5, 2013 at 20:14
  • @MightyPork The list IDs and parent IDs are used to update a Sitemap table in SQL. A user can modify the site's hierarchy (various pages) in the browser, then save the changes. Commented Aug 5, 2013 at 20:19

1 Answer 1

1

I've modified your original code. This should work for all combinations of nested lists. Instead of using children().get(), I used the native JS child methods. It will traverse everything in the list, but ignore elements unless they are <li> or <ul>. Good luck.

            var count = 0;
            var pages = [];
            var parentStack = [];

            var result = {};

            parentStack.push(0);

            function createNewLevel(obj) {
                var obj = obj || document.getElementById('sortableSitemap');

                if (obj.tagName == 'LI') {
                    ++count;
                    pages.push({
                        pId: parentStack[parentStack.length - 1],
                        urlStr: obj.id, myId: count
                    });
                }

                if (obj.hasChildNodes()) {
                    var child = obj.firstChild;
                    while (child) {
                        if (child.nodeType === 1) {

                            if (child.tagName == 'UL') {
                                parentStack.push(count);
                            }

                            createNewLevel(child);

                            if (child.tagName == 'UL') {
                                parentStack.pop();
                            }
                        }
                        child = child.nextSibling;
                    }
                }
            }

            createNewLevel();
Sign up to request clarification or add additional context in comments.

Comments

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.