Good question, and maybe not as straightforward as initially meets the eye.
First, you don't need to return additional values along with promise.
Barring synchronous errors, the entirety of the form submission's success/failure is conveyed in the promise returned by submitInlineForm()
.... but there are pifalls in that ...
- the promises returned by
jQuery.ajax()
are non standard.
- any single failure in a set of promises aggregated with
jQuery.when()
or Promise.all()
will (without measures to prevent it) cause the aggregated promise to take its error path.
... so:
- in order to count successes and failures you can reflect the promises returned by
submitInlineForm()
, otherwise any single failure will cause the promise returned by Promise.all()
to fail.
- in order to allow jqXHRs to be successfully reflected (in a standard way), you need first to normalise the multiple parameters exposed to the jqXHRs'
.then()
callbacks.
Fortunately a couple of utility functions allow the main code to be pretty straightforward.
let reflect = (promise) => {
return promise.then(function(v){ return {v:v, status: "fulfilled" }},
function(e){ return {e:e, status: "rejected" }});
};
let normalise = (jqXHR) => {
// Recastast jqXHR as native js Promise by wrapping in `Promise.resolve()`.
return Promise.resolve(jqXHR.then((response, textStatus, jqXHR) => {
// this is a jQuery success handler.
if (response.success) {
// normalise the params into one js plain object
return { response, textStatus, jqXHR };
} else {
return $.Deferred().reject(new Error('response.success was falsy')); // throw the jQuery way (not strictly necessary in jQuery v3+)
}
}, (jqXHR, textStatus, errorThrown) => {
// This is a jQuery error handler.
// Normalise the params into one js Error object.
return $.Deferred().reject(new Error(textStatus || errorThrown)); // throw the jQuery way (not strictly necessary in jQuery v3+)
}));
};
With the utilities in place, the main code is pretty simple.
let submitForm = () => {
let formsToSubmit = $('.form-inline').get().filter(submittable);
return Promise.all(formsToSubmit.map(submitInlineForm).map(normalise).map(reflect)) // Yay, the two pitfalls are overcome in a single line!
.then(outcomes => {
// Because all the promises in formsToSubmit were reflected, you will end up here regardless of any error(s).
// Now separate out the successes and errors
let successes = outcomes.filter(o => o.status === 'fulfilled').map(o => o.v.response); // array of raw ajax responses
// let successes = outcomes.filter(o => o.status === 'fulfilled').map(o => o.v.response.values); // alternatively, you might choose to extract the data of interest fom the raw responses at this point.
let errors = outcomes.filter(o => o.status === 'rejected').map(o => o.e); // array of errors
if (errors.length > 0) { // were there any errors?
return false;
} else {
// All forms were successfull (`successes` should be congruous with `outcomes`).
// Do something with the successes.
return $.ajax({...}); // or whatever
}
});
};
let submitInlineForm = $form => {
return $.ajax({
'url': $form.attr('action'),
'type': 'post'
});
};
untested