Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Randomize a sequence of div elements with jQuery

$('div.band div.member');

will give you a jQuery object containing <div> that match the selector i.e. div with class member that are descendents of a div with class band.

The jQuery object is an array-like object in that each matched element is assigned a numerical property (think like an index) of the object and a length property is also defined. To get one element is

// first element
$('div.band div.member')[0];

or

// first element
$('div.band div.member').get(0);

Instead of selecting all elements, you can specify to select a specific element according to position in the DOM. For example

// get the first div with class member element
$("div.band div.member:eq(0)")

or

// get the first div with class member element
$("div.band div.member:nth-child(1)")

EDIT:

Here's a plugin I just knocked out

(function($) {

$.fn.randomize = function(childElem) {
  return this.each(function() {
      var $this = $(this);
      var elems = $this.children(childElem);

      elems.sort(function() { return (Math.round(Math.random())-0.5); });  

      $this.detach(childElem);  

      for(var i=0; i < elems.length; i++)
        $this.append(elems[i]);      

  });    
}
})(jQuery);

Working Code:

$('button').click(function() {
  $("div.band").randomize("table tr td", "div.member");
});

(function($) {

  $.fn.randomize = function(tree, childElem) {
    return this.each(function() {
      var $this = $(this);
      if (tree) $this = $(this).find(tree);
      var unsortedElems = $this.children(childElem);
      var elems = unsortedElems.clone();

      elems.sort(function() {
        return (Math.round(Math.random()) - 0.5);
      });

      for (var i = 0; i < elems.length; i++)
        unsortedElems.eq(i).replaceWith(elems[i]);
    });
  };

})(jQuery);
body {
  background-color: #000;
  font: 16px Helvetica, Arial;
  color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="band">
  <table>
    <tr>
      <td>
        <div class="member">
          <ul>
            <li>John</li>
            <li>Lennon</li>
          </ul>
        </div>
      </td>
    </tr>
    <tr>
      <td>
        <div class="member">
          <ul>
            <li>Paul</li>
            <li>McCartney</li>
          </ul>
        </div>
      </td>
    </tr>
    <tr>
      <td>
        <div class="member">
          <ul>
            <li>George</li>
            <li>Harrison</li>
          </ul>
        </div>
      </td>
    </tr>
    <tr>
      <td>
        <div class="member">
          <ul>
            <li>Ringo</li>
            <li>Starr</li>
          </ul>
        </div>
      </td>
    </tr>
  </table>
</div>
<button>Randomize</button>

Here's an Editable Working Demo. add /edit to the URL to see the code. If you need any details about how it works, please leave a comment. It could probably do with being made more robust to handle certain situations (like if there are other child elems of the jQuery object the plugin is chianed to) but it'll suit your needs.


I modified Russ Cam's solution so that the selector is optional, and the function can be called on multiple container elements, while preserving each randomized element's parent.

For example, if I wanted to randomize all LIs within each '.member' div, I could call it like this:

$('.member').randomize('li');

I could also do it like this:

$('.member li').randomize();

So the two ways to call this are as follows:

$(parent_selector).randomize(child_selector);

OR

$(child_selector).randomize();

Here's the modified code:

$.fn.randomize = function(selector){
    (selector ? this.find(selector) : this).parent().each(function(){
        $(this).children(selector).sort(function(){
            return Math.random() - 0.5;
        }).detach().appendTo(this);
    });

    return this;
};

Minified:

$.fn.randomize=function(a){(a?this.find(a):this).parent().each(function(){$(this).children(a).sort(function(){return Math.random()-0.5}).detach().appendTo(this)});return this};

Randomization using sort does not always randomize the elements. It is better to use a shuffle method like the one from How can I shuffle an array?

Here's my updated code

(function($) {
    $.fn.randomize = function(childElem) {
        function shuffle(o) {
            for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
            return o;
        };
        return this.each(function() {
            var $this = $(this);
            var elems = $this.children(childElem);

            shuffle(elems);

            $this.detach(childElem);  

            for(var i=0; i < elems.length; i++) {
                $this.append(elems[i]);      
            }
        });    
    }
})(jQuery);

Just in case you are ok with doing it without jquery:

/** @param {HTMLElement} parent */
const shuffleChildren = (parent) => {
    const cards = [...parent.children];
    for (const child of cards) {
        const newPlace = Math.floor(Math.random() * cards.length);
        parent.insertBefore(child, cards[newPlace + 1] || null);
    }
};

(an answer unrelated to jquery was closed as duplicate of this one, so posting here)