Perkin5
Perkin5

Reputation: 399

jQuery queue not working

What I am trying to do is to clear the html on a page, insert a single div, give it a backgound image, fade it in, keep it there for a few seconds, fade it out and then return to the previous html. I'm doing this:

var body_html = $('body').html();

    $('body').queue(function(){
      $(this).empty().css('background-image','none').html('<div class="start-img"></div>');
      $(this).dequeue();
    }).queue(function(){
      $('.start-img').html('<img src="'+url+'public/img/holding.jpg">').fadeIn(1000).delay(10000).fadeOut(500);
      $('.start-img').dequeue();
    }).queue(function(){
      $(this).html(body_html).css('background-image','url("../img/paper-bg.jpg")');
      $(this).dequeue();
    });

I have spent a ridiculous amount of time googling but this seems to match the examples I've seen and it doesn't work. Firebug shows no errors. What happens is the page goes blank and the background image (holding.jpg) fades in for about one second, then fades to a blank page. When I view the generated source, only the div.start-img is present as html.

I've never used queue() before and I must have misunderstood it but can anyone set me right? Even if there is a better way of doing it, why does my code not work?

Upvotes: 0

Views: 1318

Answers (1)

klenwell
klenwell

Reputation: 7148

I'm not an expert with jQuery's queue method. (I've never used it before.) But I think I spot a couple problems here:

1. Dequeue events must be paired with same targets as the initiating queue event

So in step 2, the line:

$('.start-img').dequeue();

Should be:

$(this).dequeue();

2. You're treating asynchronous events as if they were synchronous

Again in step 2: you have a fadeIn effect chained to a long delay chained to a fadeOut effect. This is going to take some time to complete. But the next line, the dequeue call, is going to execute immediately, which I expect will immediately move the queue to the next step and wreck havoc on your sequence.

Solution

Wait until any asynchronous events have completed before making the dequeue call to move on to the next queue event.

Here's a fiddle that demonstrates a sequence of steps like that which you describe in your question: http://jsfiddle.net/klenwell/wg4jqdjs/

Here's the queue code:

var $newDiv = $('<div />').html('<h4>new block</h4>').hide();

$body
  .queue(function() {
    $body.children().fadeOut(1000, function(){ $body.dequeue(); });  
  })
  .queue(function() {
    $body.append($newDiv);
    $newDiv.fadeIn(1000, function(){ $body.dequeue(); });
  })
  .queue(function() {
    $newDiv.animate({backgroundColor: "red"}, 1500, function(){ $body.dequeue(); });
  })
  .queue(function() {
    setTimeout(function(){ $body.dequeue(); }, 2000);
  })
  .queue(function() {
    $newDiv.fadeOut(1000, function(){ $body.dequeue(); });
  })
  .queue(function() {
    $body.find('h4:eq(0)').fadeIn(1000, function(){ $body.dequeue(); });
  });

Notice how the dequeue calls are made in the on-completion callbacks of the various asynchronous events.


Addendum

It would have been a little cleaner to have just passed the dequeue call to the various effect callbacks, like this:

$body.children().fadeOut(1000, $body.dequeue);

But, unfortunately, that was raising an error in my fiddle.

Upvotes: 2

Related Questions