Question

I have this HTML list <ul> which contains list items with two different classes.

<ul id="Items">
    <li class="sw">Switchable 1</li>
    <li class="sw">Switchable 2</li>
    <li class="notsw">This should remain 3</li>
    <li class="sw">Switchable 4</li>
    <li class="notsw">This should remain 5</li>
    <li class="sw">Switchable 6</li>
</ul>

<input type="button" class="btn" value="Shuffle" />

I am trying to randomize or shuffle the order of the list items when an event is triggered (let's say a button was clicked) but only shuffle the list items with the .sw class. So far, I have achieved shuffling the list items(all of them) using a jQuery custom function. Then, I tried storing the initial indexes of the .notsw list items(I think i'm getting the right values) and used jQuery .before() to move it back after the shuffle but still I can't make it go where it should be.

Note: The list items with the .notsw class could be anywhere in the list initially.

jQuery:

$('.btn').click(function(){
    var notsws = document.getElementsByClassName("notsw"); 
    var inds = new Array();
    for(var i=0; i<notsws.length; i++){
        inds[i] =$('.notsw').eq(i).index();
    }
    $('#Items').randomize();
    for(var k=0; k<notsws.length; k++){
        var curr = inds[k];
        $('.notsw').eq(k).before($('#Items li').eq(curr));
    }
});       


$.fn.randomize = function(selector){
    var $elems = selector ? $(this).find(selector) : $(this).children(),
        $parents = $elems.parent();

    $parents.each(function(){
        $(this).children(selector).sort(function(){
            return Math.round(Math.random()) - 0.5;
        }).remove().appendTo(this);
    });

    return this;
};

I HAVE A JSFIDDLE EXAMPLE HERE

Was it helpful?

Solution

I used an alternate approach. I see that you are randomizing your list and then trying to remember whether the original elements were.

Instead of that, why don't you just shuffle elements based on whether they can be shuffled. In the sense, take an array of the indexes for the switchable elements denoted by the selector .sw and then shuffle only those indexes.

Here's how the shuffle function would look like.

function shuffle(nodes, switchableSelector) {
    var length = nodes.length;

    //Create the array for the random pick.
    var switchable = nodes.filter("." + switchableSelector);
    var switchIndex = [];

    $.each(switchable, function(index, item) {
       switchIndex[index] = $(item).index(); 
    });

    //The array should be used for picking up random elements.
    var switchLength = switchIndex.length;
    var randomPick, randomSwap;

    for (var index = length; index > 0; index--) {
        //Get a random index that contains a switchable element.
        randomPick = switchIndex[Math.floor(Math.random() * switchLength)];

        //Get the next element that needs to be swapped.
        randomSwap = nodes[index - 1];

        //If the element is 'switchable' continue, else ignore
        if($(randomSwap).hasClass(switchableSelector)) {
            nodes[index - 1] = nodes[randomPick];
            nodes[randomPick] = randomSwap;
        }
    }

    return nodes;
}

On your button click, you can simply shuffle the nodes and then re-append them to the container.

$(".btn").click(function() {
    var $nodes = $("#Items").find("li");
    shuffle($nodes, "sw");
    $("#Items").append($nodes);
});

Working fiddle present here.

OTHER TIPS

What you are doing is removing all the "sw" elements and then pushing them at the back of the list. I would create a new randomized list with the "sw" items and then add the "notsw"item at their previous indexes. You should therefore save the "notsw" indexes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top