1

I have several forms I would like to post to my server at once. Then, I want to listen for all of them to complete. If I hear them all complete successfully, I will take one action and, if I see one fail, I will take a different action.

I believe I should use jQuery's .when(): http://api.jquery.com/jQuery.when/

This post on StackOverflow shows an example on how to do it when you have all of your ajaxRequests explicitly defined: Wait until all jQuery Ajax requests are done? I am wondering if it is possible to achieve the same effect with a loop somehow?

I currently have this code, but it does not wait for all to complete:

_.each($('form'), function (form) {
            var $form = $(form);

            if ($form.valid()) {
                //  Post form data
                $.ajax({
                    url: $form.attr('action'),
                    type: $form.attr('method'),
                    data: getFormData($form),
                    success: function () {}
                    error: function(){}
                });
            }
        });

EDIT: While I've accepted an answer.. it is worth noting that the correct 'answer' was changing the design requirements. We realized that it would be extremely difficult to undo one transaction if another failed, but we had to keep all the transactions in the same state. This led us down the path that Beetroot had suggested, creating one giant model, but that added a ton of other complexities. As such, we now just have the user save before changing between tabs.

Community
  • 1
  • 1
Sean Anderson
  • 27,963
  • 30
  • 126
  • 237
  • 1
    Bad design. Submit all forms' data in one hit. One request, one promise. – Beetroot-Beetroot Apr 17 '13 at 22:30
  • Could you delve a little deeper into this? What happens if there is a lot of data to be posted and I want to not have an overly large POST? Also, some of my forms might not be dirty, so the receiving server-side method would have to accomodate a variable number of models as opposed to just having each server-side method respond individually as it receives its corresponding POST? Furthermore, I would like to have varying responses to each form's error callback. This is complicated if I only have one error callback as I have to figure out which ones have error'ed. – Sean Anderson Apr 17 '13 at 22:35
  • Unless there's a standard approach/utility for this, it's going to require a little thought, essentially involving the concatenation of all the serialized forms, complete with form ids to identify each data-set. Server-side you'll probably need some custom request parsing to separate you the individual data items per form. You will then have all the data you need to process all the forms' data and compose a composite (JSON-encoded) response including form ids to tag the data. Back client-side, loop through the response and act accordingly. Easy! :-) – Beetroot-Beetroot Apr 17 '13 at 23:33
  • 1
    Maximum POST size is determined by the server and typically measured in megabytes rather than kilobytes. You would typically need a lot of large forms to exceed the maximum. – Beetroot-Beetroot Apr 17 '13 at 23:37

1 Answers1

1

You can use jQuery.when like so;

jQuery.when.apply(jQuery, $('form').map(function () {
    var $form = $(form);

    if ($form.valid()) {
        //  Post form data
        $.ajax({
            url: $form.attr('action'),
            type: $form.attr('method'),
            data: getFormData($form),
            success: function () {}
            error: function () {}
        });
    }

    // Otherwise don't do anything.
})).done(function (form1Ajax, form2Ajax, formNAjax) {
    // All complete    
}).fail(function (form1Ajax, form2Ajax, formNAjax) {
    // One failed
});

Unfortunately, jQuery.when expects each Deferred to be given as a separate parameter, rather than an array of Deferreds; which is why we're jumping through hoops with apply.

Note also the behaviour of map(); it does not add an element to the resultant array if undefined or null is returned.

Matt
  • 74,352
  • 26
  • 153
  • 180