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.

nquincampoix
  • 508
  • 1
  • 4
  • 17
user843904
  • 31
  • 3

1 Answers1

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.

SunnyRed
  • 3,525
  • 4
  • 36
  • 57
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • 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.. – user843904 Jul 14 '11 at 06:23
  • 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! – Ben Hull Jul 14 '11 at 06:23
  • @user843904, you're absolutely right, I misread your question. I'll update my answer shortly. – Frédéric Hamidi Jul 14 '11 at 06:26
  • @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. – user843904 Jul 15 '11 at 07:43
  • Sorry for the code, i am new to stackoverflow, I put sample data in here http://jsfiddle.net/theworldiw/FaLzq/ – user843904 Jul 15 '11 at 07:44
  • @user843904, if I understand correctly, you only want to add `id` attributes and not to flatten the lists. In that case, the ideal algorithm is not the same. I'd suggest you ask another question, or maybe you try to adapt my answer to [this question](http://stackoverflow.com/q/4459143/464709), which is similar to yours. – Frédéric Hamidi Jul 15 '11 at 10:54
  • @Frédéric Hamidi, OK thank you very much, I will try first, if can't get it, will post a new question – user843904 Jul 16 '11 at 04:09