Search code examples
javascriptjquerybubble-sort

JQuery - Swapping two elements does not work after first move


I have a function to do a bubble sort among content of various divs. for each swap operation, it swaps the divs too, using JQuery Swapsies plugin. The problem is tht it does the swap once, and after that for other swap operations:

function swap(id1, id2){

$('#' +id1).swap({
  target: id2,
  opacity: "0.5",
  speed: 1000,
  callback: function() {


  }
});

}

function bubbleSort() {

var ret=[];
$(".num-div").each(function(){ ret.push($(this));});

let swapped;
do {
  swapped = false;
  for (let i = 1; i < ret.length; ++i) {

    if (ret[i - 1].html() > ret[i].html()) {
      swap(ret[i-1].attr('id'), ret[i].attr('id'));
      [ret[i], ret[i - 1]] = [ret[i - 1], ret[i]];

      swapped = true;

    }
  }
} while (swapped);
return ret;

}

In the first step where i=1 it works and swaps ret[i-1] with ret[i], but after that it does not work.


Solution

  • The swap plug-in will not process calls when it is busy with an animation. You can see that in the source code of the plug-in:

    if (options.target!="" && !swapping) {
    

    The swapping variable will be true during an ongoing animation, and that if will just skip any new animation without notice.

    Anyway, you probably want the animations to happen in sequence, not all at the same time. For that purpose I would suggest using promises and the rather new async/await syntax.

    First you would promisify the swap function, so it returns a promise. Then you add the async and await keywords at the appropriate spot, and ... it will work.

    One more caution: if your data is numerical, and you want to sort by numeric value, you need to convert strings to numbers before doing the comparison, for instance by applying the unary + like this: +ret[i].text()

    Here is a working demo:

    function swap(id1, id2){
        return new Promise(resolve => 
            $('#' +id1).swap({
              target: id2,
              opacity: "0.5",
              speed: 500,
              callback: resolve
            })
        );
    }
    
    async function bubbleSort() {
        var ret=[];
        $(".num-div").each(function(){ 
            ret.push($(this));
        });
    
        let swapped;
        do {
            swapped = false;
            for (let i = 1; i < ret.length; ++i) {
                if (ret[i - 1].text() > ret[i].text()) {
                    await swap(ret[i-1].attr('id'), ret[i].attr('id'));
                    [ret[i], ret[i - 1]] = [ret[i - 1], ret[i]];
                    swapped = true;
                }
            }
        } while (swapped);
        return ret;
    }
    
    bubbleSort().then( ret => {
        console.log($.map(ret, x => $(x).text()));
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="http://biostall.com/wp-content/uploads/2010/07/jquery-swapsies.js"></script>
    <div id="i1" class="num-div">sort</div>
    <div id="i2" class="num-div">these</div>
    <div id="i3" class="num-div">words</div>
    <div id="i4" class="num-div">in</div>
    <div id="i5" class="num-div">alphabetical</div>
    <div id="i6" class="num-div">order</div>