0

For a day now I am having a very weird problem with my set of jQuery animations.

I tried multiple approaches but all of them just give me weird bugs.

I made a jsfiddle for my example. Please check the console.log and also try seeing the animations being done in the html, it's acting very weird.

I have a menu that first closes a box by first fading out the text inside then opens another box and fades each line of text at a time.

I am trying to block the possibility of clicking on another element of a menu while there is an animation still going.

I have also tried using .promise().done(function(){... with the each function but that didn't work.

http://jsfiddle.net/XpJud/

My js file

$(document).ready(function(){

var ongoing=false;
var selected="one";

$("ul li").click(function(){

console.log("ongoing : " +ongoing);

if($(this).index() == 1 && selected != "two" && !ongoing ){
  console.log("clicked two and in");
  console.log(ongoing);
ongoing=true;
    var text=$("ul li:nth-child(1)").text();
console.log(text);    

    $("."+selected+" div").animate({"opacity": 0},1000,function(){
    $("."+selected).animate({'width': '0px'},1000,function(){
        $("."+selected).hide();
        $(".extra").animate({"color": "blue"},1000);
        $("."+text).show().animate({'width': '800px'},1000,function(){
                    selected=text;
                    $("."+selected+" div").each(function(i){ 
                     $(this).delay(i*2000).animate({"opacity":                   1},2000,function(){
                    console.log(i + " is finished");
                    if(i == 2){
                      ongoing=false; 
                    }
                   });      
                });


        }); 
  });
});


}

  else if($(this).index() == 2 && selected != "three" && !ongoing){
  console.log("clicked about and in");
   console.log(ongoing);
ongoing=true;
var text=$("ul li:nth-child(2)").text();
console.log(text);    

$("."+selected+" div").animate({"opacity": 0},1000,function(){
      $("."+selected).animate({'width': '0px'},1000,function(){
            $("."+selected).hide();
            $(".extra").animate({"color": "red"},1000);
            $("."+text).show().animate({'width': '800px'},1000,function(){
                  selected=text;
                  $("."+selected+" div").each(function(i){ 
                        $(this).delay(i*2000).animate({"opacity": 1},2000,function(){
                          console.log(i + " is finished");
                          if(i == 2){
                            ongoing=false; 
                          }
                        });
                  });
          });
      });
    });

  }


});

});

My html file

    <div class='extra'> Hi</div>

<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>

    <div id="content">

        <div class='one'>

            <div class='one-1'>test test test test</div><br>
            <div class='one-2'>test test test test</div><br>
            <div class='one-3'>test test test test</div><br>

        </div>

        <div class='two'>


            <div class='two-1'>test test test test</div><br>
            <div class='two-2'>test test test test</div><br>
            <div class='two-3'>test test test test</div><br>

        </div>


        <div class='three'>


            <div class='three-1'>test test test test</div><br>
            <div class='three-2'>test test test test</div><br>
            <div class='three-3'>test test test test</div><br>

        </div>  
  </div>

My css file

ul li{

display:inline-block;
background: red;
cursor: pointer;
}


#content{

width:100%;
}

.three{

  margin: 0 auto;

  width: 0px;
  display: none;
  height: 360px;

  text-align: center;

background: #EEE836;

font-size: 50px;
  margin-bottom: 180px;
}

.two{

  margin: 0 auto;

  width: 0px;
  display: none;
  height: 360px;

  text-align: center;

background: blue;

font-size: 50px;

  margin-bottom: 180px;
}

.one{

  margin: 0 auto;

  width: 800px;
  margin-bottom: -180px;
  height: 360px;
  background: white;
  text-align: center;

background: red;

font-size: 50px;



}
Kara
  • 6,115
  • 16
  • 50
  • 57
oxynad
  • 21
  • 1
  • 5

1 Answers1

0

(1) When you animate multiple elements at once, you want the callback to get called just one time, after the last animation is finished.

To accomplish this, where you have the following:

$("."+selected+" div").animate({"opacity": 0},1000,function(){

You can change it to:

$("."+selected+" div").animate({"opacity": 0},1000).promise().done(function(){

I got this technique from this Stackoverflow question.

(2) Before you fade something in, you must first ensure that it starts as faded out all the way. Likewise, before you show an element and then increase its width, you must ensure that it first has a width of 0. These changes can be made with the .css() function and should be performed before calling .show().

For example, where you have:

$("."+text).show().animate({'width': '800px'}...

You should have:

$("."+text).css({'width': '0px'}).show().animate({'width': '800px'}...

(3) Instead of using the (albeit simpler) technique of using .delay() for animating a list of elements sequentially, the following technique gives better results:

var i = 0;
(function() {
    var $el = $($elements[i++] || []);
    if ($el.length > 0) {
        $el.animate({ opacity: 1 }, 2000, arguments.callee);  
    } else {
        // Perform final tasks.
    }
})();

I adapted this technique from here.

DEMO ON JSFIDDLE

Community
  • 1
  • 1
John S
  • 21,212
  • 8
  • 46
  • 56
  • Thank you so much! best answer ever. And thank you for making a simpler, more clever and cleaner version of my code. – oxynad Dec 18 '13 at 05:15