jQuery split long ul list in smaller lists
Asked Answered
C

10

11

I have a long UL list I need to break up in smaller lists containing about 20 items each.

I was thinking I could use something like

$(function() {
    $("ul li:nth-child(20n)").after("</ul><ul>");
});

but that's not the case. Any idea how to use jQuery in a way that uses minimal CPU?

Crackling answered 29/10, 2009 at 15:45 Comment(1)
There is a library which does that - github.com/yairEO/listBreakerTompion
S
19

I would create document fragments with your removed lis and then reappend them to the location you want them. In this case, I reappended them to the body:

$(function(){
  var $bigList = $('#bigList'), group;
  while((group = $bigList.find('li:lt(20)').remove()).length){
    $('<ul/>').append(group).appendTo('body');
  }
});

Live Demo is at: http://jsbin.com/ejigu/33

Sutphin answered 29/10, 2009 at 16:12 Comment(3)
Just for run I tried doing this with regex instead: jsbin.com/acupof/2/edit#javascript,live ... I can't say its more elegant. :)Helot
For sheer speed, the regex solution might be better. If you switched my answer to use detach instead of remove it would keep any events that have been attached to the elements or sub-elements. That would be helpful in some situations. Though with long lists, you probably should be delegating anyways. <3zSutphin
What is group defined as, before it is used within the while loop?Katrinka
S
7

Nothing quite that simple (that I'm aware of at least) unfortunately. Try this as an alternative:

$(function() {
  $("ul").each(function() {
    var list = $(this);
    var size = 3;
    var current_size = 0;
    list.children().each(function() {
    console.log(current_size + ": " + $(this).text());
      if (++current_size > size) {
        var new_list = $("<ul></ul>").insertAfter(list);
        list = new_list;
        current_size = 1;
      }
      list.append(this);
    });
  });
});

You could no doubt turn this into a function that takes the chunk size as an argument but I leave that as an exercise for the reader.

Solarium answered 29/10, 2009 at 16:5 Comment(0)
K
3

Here's a working example, just change the mod 5 to mod 20.

<html>
<script type="text/javascript" src="jquery-1.3.2.js"></script>

<script type="text/javascript">

function onLoad(){
   var itemindex = 0;
   var Jlistobj = null;
   $('#list li').each(function()
   {
      if (itemindex % 5 == 0)
      {
         Jlistobj = $("<ul></ul>");
      }
      Jlistobj.append($(this));
      $('#out_div').append(Jlistobj);
      itemindex++;
   });
}

</script>
<body onLoad="onLoad()">

<ul id="list">
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
<li>item7</li>
<li>item8</li>
<li>item9</li>
<li>item10</li>
<li>item11</li>
<li>item12</li>
<li>item13</li>
<li>item14</li>
<li>item15</li>
<li>item16</li>
<li>item17</li>
<li>item18</li>
<li>item19</li>
<li>item20</li>
</ul>

<div id="out_div"></div>

</body>

</html>
Ked answered 29/10, 2009 at 16:23 Comment(0)
M
2

function:

$.fn.splitUp=function(splitBy,wrapper) {
    $all= $(this).find('>*');
    var fragment=Math.ceil($all.length/splitBy);  
    for(i=0; i< fragment; i++) 
        $all.slice(splitBy*i,splitBy*(i+1)).wrapAll(wrapper);
    return $(this);
}

usage:

$('ul#slides').splitUp(4,'&lt;li class=splitUp&gt;&lt;ul&gt;')

or:

$('div#slides').splitUp(3,'&lt;div/&gt;')
Mateya answered 23/3, 2010 at 19:15 Comment(1)
If you make it recursive it is even shorterWreckage
T
1

this one splits the menu in to pieces of approximately equal length function splitMenu(menu_id, pieces) {

        var $menu = $(menu_id), group;
        var splitItem = 0, totItemLen = 0, cumlen = 0;

        $($menu).find('li').each(function(){ totItemLen = totItemLen + $(this).width(); });

        $($menu).find('li').each(function(i){
            cumlen = cumlen + $(this).width();
            if ( totItemLen/pieces < cumlen && splitItem == 0) splitItem = i;  
        });

        while((group = $($menu).find('li:lt(' + splitItem + ')').remove()).length){
                $('<ul/>').attr('class',$($menu).attr('class')).append(group).appendTo($($menu).parent());
          }

        $($menu).remove();  
    }  
    splitMenu('#menu-footermenu', 2);
Thiele answered 3/8, 2012 at 12:34 Comment(0)
L
1

Just another version as a jQuery plugin:

jQuery.fn.splitList = function(num) {
  var sublist;
  while((sublist = this.find('li:gt('+(num-1)+')').remove()).length){
    this.after($('<ul/>').append(sublist));
  }
};
Ly answered 5/6, 2013 at 11:12 Comment(0)
B
0

Here is another option - I haven't profiled any of the above, so go with whatever is fastest of course. It assumes the ul in question has the id of #list.

     var listItemsPerList = 10;
     var listItems = $("ul > li").length;

     for (var i = 0; i < Math.round(listItems / listItemsPerList); i++) {
         var startingItem = i * listItemsPerList;
         var endingItem = (i + 1) * listItemsPerList;
         if (endingItem > listItems) { endingItem = listItems };
         $("ul > li").slice(startingItem, endingItem).wrapAll("<ul></ul>");
     }

     $("ul#list").replaceWith($("ul#list").children());
Billion answered 29/10, 2009 at 16:53 Comment(0)
C
0

you can try something like this:

$("ul").each(function(k,v)){
    split_list(v);
}

function split_list(list){
    var li_num = $(list).find("li").length;
    if(li_num > 20){
        var new_list = $("<ul></ul>");
        $(list).after(new_list);
        new_list.append($(list).find("li:gt(20)"));
        if(new_list.find("li").length > 20){
            split_list(new_list);
        }
    }
}

LE: I think it can be further refined by finding up front how many new list will be createt, create those lists and move blocks of ~20 li's into the new created lists so they will be moved only once.

Conlan answered 29/10, 2009 at 17:19 Comment(0)
A
0

Here's a extension of the jQuery prototype ($.fn) object to provide a new method that can be chained to the jQuery() function.

I needed to functionality where I needed to add an element between the list that I split. That has been added as an optional parameter.

An example is available at http://jsfiddle.net/roeburg/5F2hW/

The usage of the function is like so:

 $("ul").customSplitList(5);

The function is defined as follows:

// Function definition
(function ($) {
    // Function is defined here ...
    $.fn.customSplitList = function (indexToSplit, elementToAddInBetween) {
        // Holds a reference to the element(list)
        var that = this;
        var subList, newList, listLength;

        // Only continue if the element is a derivitive of a list
        if ($(that) && ($(that).is("ul") || $(that).is("ol"))) {

            // Additionally check if the length & the split index is valid
            listLength = $(that).children().length;

            if ($.isNumeric(indexToSplit) && indexToSplit > 0 && indexToSplit < listLength) {
                // Based on list type, create a new empty list
                newList = $($(that).clone(true)).empty();

                while ((subList = this.find('li:gt(' + (indexToSplit - 1) + ')').remove()).length) {
                    newList.append(subList);
                }

                if (elementToAddInBetween && $(elementToAddInBetween)) {
                    that.after(newList);
                    newList.before(elementToAddInBetween);
                } else {
                    that.after(newList);
                }
            }
        }
    };

})(jQuery);

Hope this helps.

Amniocentesis answered 9/7, 2014 at 8:24 Comment(0)
R
0

Something like this:

var lis = $("ul > li");
for(var i = 0; i < lis.length; i+=20) {
  lis.slice(i, i+20).wrapAll("<ul></li>");
}
$("ul > ul").unwrap();

Working Demo

Rosser answered 16/6, 2015 at 7:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.