tags:

views:

658

answers:

3

Hi,

I have this code and every 3 's I need to wrap with a div

(original)

<div id="entries"> 
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
</div>

(should become)

<div id="entries"> 
<div>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
</div>
<div>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
</div>
<div>
<a class="thumbnaila"><img class="thumbnail" alt="" src="blabla"/></a>
</div>
</div>
A: 

Hi,

Apply a class to each "sub-div" that fills the content horizontally, and give it clrar:both; as css atribute, and it will display the way you want. In case you want to display it vertically, apply float:left; instead.

yoda
+2  A: 

Mighty work and might not be the smartest thing to do:

var $entries = $("#entries");
var $div = $('<div></div>').appendTo($entries);
while($div.next().length > 0){
  $div.append($div.nextAll().slice(0,3));
  $div = $('<div></div>').appendTo($entries);
}
svinto
this doesn't appear to work as intended. It appends a `<div> to the end of the entries `<div>` and then checks that there is a next element, which there wouldn't be, as the `<div>` is appended to the end.
Russ Cam
+1  A: 

I've put together this plugin that does the job nicely

(function($){

   $.fn.wrapChildren = function(options) {

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

 return this.each(function() {
  var elems = $(this).children(options.childElem);
  var arr = [];

  elems.each(function(i,value) {
    arr.push(value);
    if (((i + 1) % options.sets === 0) || (i === elems.length -1))
   {
     var set = $(arr);
     arr = [];
     set.wrapAll($("<" + options.wrapper + ">"));
   }
  });
    });

  }

})(jQuery);

You pass in an options object defining

  • childElem - the element nodeType of the immediate children to wrap
  • sets - how you want to group the child elements. For example, sets of 3 in your case. Default is 1
  • wrapper - the element to wrap the child elements in. default is <div>

Use like so on your test data.

$(function() {

  $('#entries').wrapChildren({ childElem : 'a' , sets: 3});

});

Here's a Working Demo to play with. Add /edit to the URL to play with the code.

I'm tempted to make this into a more fully fledged plugin, if it proves useful.

Russ Cam
Kudos for providing a flexible solution.
Nathan Long
What's interesting with the solution is that any child elements not matched by the childElem nodeType will be moved in the DOM to after the last wrapped child set. The thing to note in using this then is that ideally, the childElems you want to wrap should be contiguous, otherwise the result may not be what you are expecting. If I were to rewrite this, then perhaps I would do it so that any child elements not matched by childElem are also moved into the appropriate wrapper based on their position relevant to the matched childElems
Russ Cam