views:

144

answers:

5

I have what I thought was a relatively easy Ajax/animation that I'm adding to a client site to select between projects for display as images. The flow goes something like this:

  1. User clicks on a thumbnail in a project overview (pHome).
  2. Using jQuery, ajax load in an XML file with the image, caption and project description data (project1).
  3. Construct the HTML from the XML file and inject it into the DOM (div id="project1").
  4. Animate and (4.5) fade out pHome.
  5. Fade in project1.
  6. Add a 'puff' effect to the thumbnail that brought the user to the project.

All of these things need to happen synchronously, but I can't find the right flow for the functions. Attaching all of these steps to the user click fades out pHome before the animation completes, and the 'puff' effect fires before the project1 div is even visible.

As it is, I have functions for all of these steps, and it seems like a real mess. What I'm asking for is some best-practice way of structuring these functions so they all happen synchronously (with the possible exception of 2 & 3). Just as an aid, here's the pseudocode for my problem:

$('#thumbnail').live('click', function(){
    loadXML(thumbnail_id);
    makeHMTL(data);
    $('pHome').animate({blah}).fadeOut();
    $('project1').fadeIn();
    $('thumbnail_id').puff();
});

I know this is obviously a bad way to do it - but I can't figure out how to nest/structure the functions to make them all synchronous. And really I'd like an answer that gives me some way to structure my functions in the future to avoid rat-nests. Educate me! :)

A: 

You can use a callback to sequence animations like so:

$('#Div1').slideDown('fast', function(){ $('#Div2').slideUp('fast'); });

Also see http://stackoverflow.com/questions/461912/jquery-finish-one-animation-then-start-the-other-one

Soviut
A: 

The animated, fadeIn and puff events/actions should all have callback options of their own that are called when they're complete. So you'd need to nest those as well and not chain them as you have.

$("#pHome").animate({}, fuction(){
    $("#project1").fadeIn(500, function(){
     $("#thumbnail_id").puff();
    });
});
WesleyJohnson
A: 
$("#thumbnail").live("click",function() {
    $.ajax({
     type: "GET",
     url: "myUrl.ashx",
     data: { param1: 1, param2: 2 },
     success: function(data, textStatus) {
      buildAndAppend(data); // Make sure it starts hidden.
      $("#Element").show("puff", {}, "slow", function() {
       anythingElse();
      });
     }
    });
});
ChaosPandion
+2  A: 

Nesting animation function is one way to do but can be nasty when you do a lot of them and you'll easily lose overview.

An option is to pack them all into an object and pass reference to the callback as such:

$('#thumbnail).live('click', animation.step1);

var animation = {
    step1: function() {
         $("#Element").show("puff", {}, "slow", animation.step2);
    },
    step2: function() {
         $("#Element").hide("linear", {}, "fast", animation.step3);
    },
    step3: function() {
         $("#Element").show("bounce", {}, 500);
    }
}

Or as an alternative you can use the built in animation queues like this:

$("#go1").click(function(){
   $("#block1").animate( { width:"90%" }, { queue:true, duration:100 } )
               .animate( { fontSize:"24px" }, 1500 )
               .animate( { borderRightWidth:"15px" }, 1500);
})

Also check the documentation: link

Mallox
+1  A: 

I would recommend you to make a callback function parameter in your loadXML function, for being able to execute the makeHTML function and your effects when the XML data is loaded from the server.

For the animations, you can execute the following animation on the previous one callback, for example:

$('#thumbnail').live('click', function(){
    loadXML(thumbnail_id, function (data) { // data is loaded
      makeHMTL(data);
      $('pHome').animate({blah}, function () {
        $(this).fadeOut();
      });

      $('project1').fadeIn('slow', function () {
        $('thumbnail_id').puff();
      });

    });
});

Your loadXML function may look like this:

  function loadXML (thmbId, callback) {
    $.post("/your/page", { thumbnail: thmbId }, function (data) {
      callback.call(this, data);
    });
  }
CMS