Wrap every 3 divs in a div
Asked Answered
L

6

88

Is it possible to use nth-child selectors to wrap 3 divs using .wrapAll? I can't seem to work out the correct equation.

so...

<div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
</div>

becomes...

<div>
   <div class="new">
        <div></div>
        <div></div>
        <div></div>
   </div>
   <div class="new">
        <div></div>
        <div></div>
        <div></div>
   </div>
</div>
Lucius answered 29/7, 2010 at 20:9 Comment(1)
gist.github.com/3181731 A nice jQuery plugin to do exactly that. Hope you'll find it useful.Beitnes
F
184

You can do it with .slice(), like this:

var divs = $("div > div");
for(var i = 0; i < divs.length; i+=3) {
  divs.slice(i, i+3).wrapAll("<div class='new'></div>");
}

You can try out a demo here, all we're doing here is getting the elements you want to wrap and looping through them, doing a .wrapAll() in batches of 3 then moving to the next 3, etc. It will wrap 3 at a time and however many are left at the end, e.g. 3, 3, 3, 2 if that's the case.

Fraunhofer answered 29/7, 2010 at 20:10 Comment(5)
I'd make this a function and make the number of wrapped divs an argument. Something like applyDivGrouping( divs, divsPerGroup );Minard
Wow! Thanks for the prompt reply. Couple of things... So, just for clarification - this isn't possible using nth-child? &.. As a complete jQuery novice - how do I get this to function? Do I wrap it in a jQuery(function($)...? Many thanksLucius
@Lucius - Nope :nth-child() doesn't lend it self well to this, as for calling this, just wrap it in a $(function() { }); if you want to run it on document.ready, otherwise call it when you want to run it :)Fraunhofer
how can we we slice and wrap the divs with the specefic classGlut
@Fahad , as per NickCraver logic, you may simply edit little piece of code var divs = $("div > .classname"); OR var divs = $("div .classname"); ThanksBrookebrooker
N
23

I've written a generic chunk function that makes this quite easy to do:

$.fn.chunk = function(size) {
    var arr = [];
    for (var i = 0; i < this.length; i += size) {
        arr.push(this.slice(i, i + size));
    }
    return this.pushStack(arr, "chunk", size);
}

$("div > div").chunk(3).wrap('<div class="new"></div>');

$.fn.chunk = function(size) {
  var arr = [];
  for (var i = 0; i < this.length; i += size) {
    arr.push(this.slice(i, i + size));
  }
  return this.pushStack(arr, "chunk", size);
}

$("div > div").chunk(3).wrap('<div class="new"></div>');
div > div {
  width: 50px;
  height: 50px;
  background: blue;
  margin: 2px;
  float: left;
}

div.new {
  background: red;
  height: auto;
  width: auto;
  overflow: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
</div>
Numinous answered 22/6, 2015 at 4:54 Comment(0)
E
8

The Plugin

$(function() {
    $.fn.EveryWhat = function(arg1) {
        var arr = [];
        if($.isNumeric(arg1)) {
            $.each(this, function(idx, item) {
                var newNum = idx + 1;
                if(newNum%arg1 == 0)
                arr.push(item);
            });
        }
        return this.pushStack(arr, "EveryWhat", "");
    }
});

How to use it.

Call EveryWhat() on the element and put in a number for every element you would like to collect.

$("div").EveryWhat(2).wrapInner('<div class="new" />');

wrapinner's quotes should have a properly formatted <div class="new" /> with a class and closing tag. Stackoverflow prevents me from showing what that looks like but here is a link of a self closing div.

What it should look like

That will wrap every other number that you specified. I'm using jquery 1.8.2. so remember use selector call EveryWhat(3) and a number for every time. Of course putting it at the bottom of the page or wrapping it in a

$(document).ready(function() {  
    //place above code here
});

You could use every nth and then .wrapInner('<div class="new" />') for the same results.

Electric answered 7/11, 2012 at 22:26 Comment(1)
You can already do this with $('div > div:nth-child(3n)') and doesn't actually result in two groups of three elements.Hodgson
E
7

Here is a more usable version of Nick's above:

window.WrapMatch = function(sel, count, className){
  for(var i = 0; i < sel.length; i+=count) {
    sel.slice(i, i+count).wrapAll('<div class="'+className+'" />');
  }
}

You would use this like:

var ele = $('#menu > ul > li'); 
window.WrapMatch(ele, 5, 'new-class-name');

window should be replaced with your Handlers namespace, of course.

Updated: A slightly better version that leverages jQuery

(function($){
  $.fn.wrapMatch = function(count, className) {
    var length = this.length;
    for(var i = 0; i < length ; i+=count) {
      this.slice(i, i+count).wrapAll('<div '+((typeof className == 'string')?'class="'+className+'"':'')+'/>');
    }
    return this;
  }; 
})(jQuery);

Use like:

$('.list-parent li').wrapMatch(5,'newclass');

The second parameter for the wrapper name is optional.

Earsplitting answered 18/10, 2013 at 1:35 Comment(0)
Y
1
$(function() {
    $.fn.WrapThis = function(arg1, arg2) { /*=Takes 2 arguments, arg1 is how many elements to wrap together, arg2 is the element to wrap*/

        var wrapClass = "column"; //=Set class name for wrapping element

        var itemLength = $(this).find(arg2).length; //=Get the total length of elements
        var remainder = itemLength%arg1; //=Calculate the remainder for the last array
        var lastArray = itemLength - remainder; //=Calculate where the last array should begin

        var arr = [];

        if($.isNumeric(arg1))
        {
            $(this).find(arg2).each(function(idx, item) {
                var newNum = idx + 1;

                if(newNum%arg1 !== 0 && newNum <= lastArray){
                    arr.push(item);
                }
                else if(newNum%arg1 == 0 && newNum <= lastArray) {
                    arr.push(item);
                    var column = $(this).pushStack(arr);
                    column.wrapAll('<div class="' + wrapClass + '"/>'); //=If the array reaches arg1 setting then wrap the array in a column
                    arr = [];
                }
                else if(newNum > lastArray && newNum !== itemLength){ //=If newNum is greater than the lastArray setting then start new array of elements
                    arr.push(item);
                }
                else { //=If newNum is greater than the length of all the elements then wrap the remainder of elements in a column
                    arr.push(item);
                    var column = $(this).pushStack(arr);
                    column.wrapAll('<div class="' + wrapClass + '"/>');
                    arr = []
                }
            });
        }
    }
});

I took Kyle's plugin idea and extended it to wrap automatically and take two arguments. It didn't work for me to begin with, but I got it running with a few edits and additions to the code.

To invoke the function just use the parent element of what you want to wrap and then set your arguments as follows.

$('#container').WrapThis(5, 'li');

The first argument is how many elements you want to wrap together and the second argument is the element type you would like to wrap.

You can change the class of the wrapping element in the main function under the variable wrapClass.

Yetah answered 7/11, 2013 at 2:54 Comment(0)
P
0

I have prepared this answer for another question that was duplicate of this one. So maybe my variant will be usefull for some one:

I think the solution to wrap all three elements is:

var $lines = $('.w-col'), // All Dom elelements with class .w-col
     holder = []; //Collect DOM elelements

$lines.each(function (i, item) {
  holder.push(item);

  if (holder.length === 3) {
    $(holder).wrapAll('<div class="w-row" />');
    holder.length  = 0;
  }
});

$(holder).wrapAll('<div class="w-row" />'); //Wrap last elements with div(class=w-row)

I have wrote the same code at jsbin with some improvements http://jsbin.com/necozu/17/ or http://jsbin.com/necozu/16/

Popovich answered 22/1, 2015 at 12:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.