user843904 user843904 - 5 months ago 22
Javascript Question

Jquery recursive function combine nested li into one

I am trying to convert a nested li into one single li using recursive method using jquery

html as follows

<ul>
<li>item-1
<ul>
<li>item-1.1</li>
</ul>
</li>
<li>item-2
<ul>
<li>item-2.1</li>
<li>item-2.2
<ul>
<li>item-2.2.1</li>
<li>item-2.2.2</li>
</ul>
</li>
</ul>
</li>
<li>item-3
<ul>
<li>item-3.1</li>
</ul>
</li>
<li>item-4</li>
<li>item-5</li>
</ul>


Final single li as below

<ul>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
<li>item-1.1</li>
<li>item-2.1</li>
<li>item-2.2</li>
<li>item-3.1</li>
<li>item-2.2.1</li>
<li>item-2.2.2</li>
</ul>


basically loop through each level then append to the end of the list.
Any ideas how I can achieve this? so it can handle any level of the list item.

Thanks in Advanced.

Answer

Here is a recursive approach that will give the output you're looking for:

function recurseFetchListItems($ul)
{
    var $li = $ul.remove().children("li").remove();
    if ($li.length) {
        $li = $li.add(recurseFetchListItems($li.children("ul")));
    }
    return $li;
}

It uses add() to accumulate the different levels of list items, while removing each level from the document. It also uses children() instead of find() in order to process a single depth level per call.

From there, you only have to start from the first <ul> element, add the cumulated set of list items back to the document, and wrap them in a new <ul> element:

$(document).ready(function() {
    recurseFetchListItems($("ul:first")).appendTo("body").wrapAll("<ul>");
});

You can see the results in this fiddle.



Original (misguided) answer follows:

You don't really need a recursive function to do that, because whole DOM element trees can be matched with a single selector. For instance, $("li") matches all the list items, whatever their depth is.

So, to achieve what you want, we only need to match all the <li> elements, remove their parent <ul> elements from the document, then wrap the list items into a new <ul> element using wrapAll() and add that element back:

$(document).ready(function() {
    $("li").parent().remove().end().appendTo("body").wrapAll("<ul>");
});

You can see the results in this fiddle.