2

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.

1 Answer 1

5

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.

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

7 Comments

Hi, Thank you for your help. However it not quite what I wanted. The result list I am trying to get is 1|2|3|4|5|1.1|1.2|...etc. display all first level item, then append all second level item. then third..
I'm not sure how important the order is, but this doesn't match the desired output order in the example code... Shame, cause this is otherwise nice and clean!
@user843904, you're absolutely right, I misread your question. I'll update my answer shortly.
@Frédéric Hamidi, hi, come back to this question, not sure if you can help me again with this, I am now trying to add an id attribute for each level and sublevel of the list, that I come up with now is var id = 0; function createMenu($ul) { id ++; var $li = $ul.children("li").remove(); if ($li.length) { $li.first().attr('id', 'id-'+id); $li = $li.add(createMenu($li.children("ul").remove())); } return $li; } this only gives me id for each level. Not sure my explanation is make sense. Thanks in Advanced.
Sorry for the code, i am new to stackoverflow, I put sample data in here jsfiddle.net/theworldiw/FaLzq
|

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.