Wrap child elements in groups in jQuery

A while ago, I answered a Stack Overflow question about how to wrap child elements matching some selector into groups of a specified size. I had a need for this again recently so I went back to the code, tidied it up and have come up with a slightly more refined plugin.

// Copyright (c) 2011 Russ Cam
// -------------------------------------------------------
// Dual licensed under the MIT and GPL licenses.
//   - http://www.opensource.org/licenses/mit-license
//   - http://www.opensource.org/licenses/gpl-3.0
(function($){
    $.fn.wrapChildren = function(options) {

        options = $.extend({
                              childElem : undefined,
                              groupSize : 1,
                              wrapper : '<div>'
                            }, options || {});
                            
        if (options.childElem === undefined) return this;

        return this.each(function() {
            var elems = $(this).children(),
                len = pos = 0;
            
            elems.each(function(i,value) {
                len += $(value).is(options.childElem)? 1 : 0;                    
                if (len > 0 && (len % options.groupSize === 0) || (i === elems.length - 1)) {          
                  elems.slice(pos,i + 1).wrapAll(options.wrapper);
                  len = 0;
                  pos = i + 1;
                }
            });
        }); 
        
    }
})(jQuery);

You call the plugin on a matched set and pass it a selector for the child element you wish to group along with a number for how many of the matching child elements should be in a group and a string representing the element in which you wish to group them. Child elements that do not match the passed child element selector will be ignored and will be placed into a group that matches their contiguous position within the child elements.Take a look at an example up on js fiddle, or copy/paste the code below into a file and run locally. Hope this helps :)

<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<title>wrapChildren Demo</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
	.wrapper { background-color: red; margin: 5px; }
</style>
<script type="text/javascript">
(function($){
    $.fn.wrapChildren = function(options) {

        options = $.extend({
                              childElem : undefined,
                              groupSize : 1,
                              wrapper : '<div>'
                            }, options || {});
                            
        if (options.childElem === undefined) return this;

        return this.each(function() {
            var elems = $(this).children(),
                len = pos = 0;
            
            elems.each(function(i,value) {
                len += $(value).is(options.childElem)? 1 : 0;                    
                if (len > 0 && (len % options.groupSize === 0) || (i === elems.length - 1)) {          
                  elems.slice(pos,i + 1).wrapAll(options.wrapper);
                  len = 0;
                  pos = i + 1;
                }
            });
        }); 
        
    }
})(jQuery);
$(function() {
  $('div').wrapChildren({ childElem : 'a' , groupSize: 4, wrapper : '<div class="wrapper">'});
});
</script>
</head>
<body>
	<p>anchors wrapped in groups of 4 including non-matching child elements</p>
	<div>
		<a href="#">1</a>
		<a href="#">2</a>
		<p>Child element that will be ignored</p>
		<a href="#">3</a>
		<a href="#">4</a>
		<p>Another that will be ignored</p>
		<a href="#">5</a>
		<a href="#">6</a>
		<a href="#">7</a>
		<p>Yet another that will be ignored</p>
		<a href="#">8</a>
		<p>And another</p>
		<a href="#">9</a>
		<a href="#">10</a>
	</div>
	<br/>
	<p>anchors wrapped in groups of 4</p>
	<div>
		 <a href="#">1</a>
		 <a href="#">2</a>
		 <a href="#">3</a>
		 <a href="#">4</a>
		 <a href="#">5</a>
		 <a href="#">6</a>
		 <a href="#">7</a>
		 <a href="#">8</a>
		 <a href="#">9</a>
		 <a href="#">10</a>
	 </div>
</body>
</html>

Comments

comments powered by Disqus