tags:

views:

118

answers:

4

I am using the jQuery UI tabs where each tab has a different form on it. After the user enters various pieces of data, they submit the entire set of tabs so that each tab posts to the server asynchronously. This works well, and I have no problems here.

However, where I run into a problem is that, the last form that I post has to happen AFTER all the other posts complete. General idea is like this:

postForm(0, "#Form1");
postForm(1, "#Form2");
postForm(2, "#Form3");
postForm(3, "#Form4");
$.post('Project/SaveProject', function (data) {
    $('<div class="save-alert">The current project has been saved.</div>')
    .insertAfter($('#tabs'))
    .fadeIn('slow')
    .animate({ opacity: 1.0 }, 3000)
    .fadeOut('slow', function () {
        $(this).remove();
    });
});

The postForm function does a little bit of processing and then makes an AJAX $.post call. The last $.post performed here (to 'Project/SaveProject') must wait until those other posts are completed. What is the best way to go about doing that?

+1  A: 

Callbacks:

Define postForm to take a callback:

function postForm(ind, id, callback)
{
  // ...
  $.post(url, function()
  {
    // ...
    callback();
  });
}

Then do something like the below. You can use recursion to write it in a less hard-coded way, which might be particularly useful if there are more forms.

postForm(0, "#Form1", function()
{
    postForm(1, "#Form2", function()
    { 
        postForm(2, "#Form3", function()
        {
            postForm(3, "#Form4", function()
            {
                $.post('Project/SaveProject', function (data) {
                    $('<div class="save-alert">The current project has been saved.</div>')
                        .insertAfter($('#tabs'))
                        .fadeIn('slow')
                        .animate({ opacity: 1.0 }, 3000)
                        .fadeOut('slow', function () {
                            $(this).remove();
                        });
                });
            });
        });
    });
});
Matthew Flaschen
Thanks for the response. I had originally considered this, but then decided it was a bit too cumbersome to work with. (+1)
JasCav
+2  A: 

You can just use the .ajaxStop() event that fires when all the other AJAX POSTs finish, assuming you're doing no other AJAX work then, like this:

postForm(0, "#Form1");
postForm(1, "#Form2");
postForm(2, "#Form3");
postForm(3, "#Form4");
$(document).ajaxStop(function() {
  $.post('Project/SaveProject', function (data) {
    $('<div class="save-alert">The current project has been saved.</div>')
    .insertAfter($('#tabs'))
    .fadeIn('slow')
    .animate({ opacity: 1.0 }, 3000)
    .fadeOut('slow', function () {
      $(this).remove();
    });
  });
  $(this).unbind('ajaxStop');
});

.ajaxStop() fires when all AJAX requests that are running complete, so it'll only fires when all of those POSTs have returned, jQuery keeps a count internally ($.active, $.ajax.active in jQuery 1.5) to determind how many simultaneous AJAX requests are outstanding...when it gets back to 0 this event fires.

This approach lets you do the other form submissions simultaneously, and do the final form ASAP after.

Nick Craver
A: 

The problem with ajaxStop is that it will fire every time any ajax is done. An alternative is implementing your own method stack like this:

var stack = []
postForm(var1, var2){
    stack.push(1);
    //Do postForm stuff
    stack.pop();
    if (stack == undefined){
        //Call the last post method
    }
}
postForm(0, "#Form1");
postForm(1, "#Form2");
postForm(2, "#Form3");
postForm(3, "#Form4");
$.post('Project/SaveProject', function (data) {
    $('<div class="save-alert">The current project has been saved.</div>')
    .insertAfter($('#tabs'))
    .fadeIn('slow')
    .animate({ opacity: 1.0 }, 3000)
    .fadeOut('slow', function () {
        $(this).remove();
    });
});
Pjotrovitz
`ajaxStop()` will only fire when *all* AJAX requests complete, and I'm unbinding it the first time it runs, can you elaborate on how this would possibly be a problem? Also your example won't work, because `stack` will be an empty array, not `undefined` :)
Nick Craver
Didn't see the unbind at the bottom there, apologize for that. Depending on the app, there may be a lot of ajax calls flying around, and in situations where you need absolute control I would make my own call stack for my workflow. Of course, your code also works (at least if there aren't any ajax calls earlier in the application, where you would have to define the handler in the postForm method)
Pjotrovitz
@Pjotrovitz - I'm not binding the handler until this batch of requests is fired off either :)
Nick Craver
A: 

You could always make all the posts synchronous using something like


$.ajax({
   type: "POST",     
   async: false,
   url: "",
   ...

of course it wouldnt be as fast but it does solve your problem if $(document).ajaxStop is not an option

Nick