0

I have written a little script that randomly shuffles a series of divs - this works as expected (or hoped).

My problem is in the implementation. I want the divs to fade out, to be shuffled and to fade in again. What I have found is that the function moveBox() executes concurrently with any animation. I have tried calling the it as a callback function to all the elements (fadeOut, delay and fadeIn) in the animation, but always with the same effect - the shuffling and redistribution of the divs happens during the animation, and is therefore visible.

I have a solution (var ts=timeOut...) which makes the shuffle happen while the divs are hidden, but I am not convinced that this is the best solution.

I would like to know how to control the order of execution of functions and whether they should execute concurrently or in sequence. My code :

<style>
    .tester{
        float:left;
        width:100px;
        height:100px;
        margin:5px;
        }
    .tester p{text-align:center;
        margin-top:20px;
    }
    .one{background-color:red;}
    .two{background-color:yellow;}
    .three{background-color:teal;}
    .four{background-color:blue;}
    .five{background-color:green;}
    .six{background-color:silver;}
</style>

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function(){
        var anibase=jQuery(".tester").length;
        jQuery(".tester").fadeOut(1000);
        function moveBox(){
            function shuffle(){
                for (i = 0; i <= (anibase - 2); i++) {
                    mover = Math.floor(Math.random() * (anibase - i));
                    if (mover != 0) {
                        mover = mover + i;
                        jQuery(".tester:eq(" + mover + ")").insertBefore(".tester:eq(" + i + ")");
                    };
                };
            };
            jQuery(".tester").fadeOut(1500).delay(500).fadeIn(1500);
            var ts = setTimeout(shuffle,1500);
            var t=setTimeout(moveBox,5000);
        };
        moveBox();
    });

</script>
<body>
    <div class="tester one">
        <p>box 1</p>
    </div>
    <div class="tester two">
        <p>box 2</p>
    </div>
    <div class="tester three">
        <p>box 3</p>
    </div>
    <div class="tester four">
        <p>box 4</p>
    </div>
    <div class="tester five">
        <p>box 5</p>
    </div>
    <div class="tester six">
        <p>box 6</p>
    </div>
</body>

thanks in advance

Nick
  • 23
  • 1
  • 5

1 Answers1

0

JQuery has the ability to nest functions, effectively controlling the order of execution.

First off although it is valid to nest functions in Javascript in this case it is not necessary, consider the following code:

<script type="text/javascript">

  jQuery(document).ready(function(){
    moveBox();  //call the function that will do the work and then setTimeout
  });



  function moveBox(){
    jQuery(".tester").fadeOut("slow",function(){
      shuffle();
      $(this).fadeIn("slow");
      return;
    });
    var t=setTimeout(moveBox,5000);
  }

  function shuffle(){
    var anibase=jQuery(".tester").length;
    for (i = 0; i <= (anibase - 2); i++) {
      mover = Math.floor(Math.random() * (anibase - i));
      if (mover != 0) {
        mover = mover + i;
        jQuery(".tester:eq(" + mover + ")").insertBefore(".tester:eq(" + i + ")");
      }
    }
  }
</script>

The important part here to look at is this:

jQuery(".tester").fadeOut("slow",function(){
  shuffle();
  $(this).fadeIn("slow");
  return;
});

This will instruct jQuery to

  1. Fade Out the .tester element
  2. When the fade out is complete execute shuffle()
  3. Then fade the elements back in

You can see further examples of this in the fadeOut documentation, some of the examples show chained events

Also by keeping your function definitions separate it makes it much easier to read.

gruntled
  • 2,684
  • 19
  • 16
  • I'll try it, thanks - I'm often reticent about defining functions after calling them - I seem to get error messages telling me "xy is not a function" ! But I agree that if I can get it right it'll make the code more readable. – Nick May 08 '11 at 13:59
  • If you were to call moveBox() outside of $(document).ready() before the definition of function moveBox().... then you would get "moveBox is not a function". But since moveBox is inside the $(document).ready it will only be executed after everything is loaded and the document enters the "ready" state. – gruntled May 08 '11 at 14:09
  • This is very useful which is why I now have more questions! I didn't realise that you could declare functions outside doc ready... It works but I get a warning "unknown pseudo class eq" in console. I need the anibase variable to be available for other routines, so I'm not sure where I should put it. Are there other means than using call back functions to chain the execution of functions ? – Nick May 08 '11 at 22:31
  • well when it comes to scope the anibase variable only exists inside the shuffle() function. outside of that function it does not exist. so if you need it in another function you can create it again within the scope of that function. Or if the number of .tester elements doesn't change hard code it. And a third option would be to replace any location where the anibase variable is needed with a function call to getAnibase() which returns jQuery(".tester").length; – gruntled May 08 '11 at 22:39
  • thanks - I'm busy trying to understand John Resig's chapter on closure and scope ! (in "Learning jQuery 1.3") – Nick May 09 '11 at 07:45