我有一个主要表格和多个相关的内联表格。提交主表单时,所有其他内联表单都应一起提交。
但是,如果任何内联表单失败(我们在响应中将其标记出来),则不会提供主表单。
问题是submitInlineForm
返回了诺言。我们如何传递表单提交是否成功,以便我们可以在submitForm
中进行处理?
let submitForm = $form => {
let formsToSubmit = [];
$('.form-inline').each(function () {
const $f= $(this);
if (submittable($f)) formsToSubmit.push(submitInlineForm($f));
});
$.when(formsToSubmit).done(() => {
if (!allFormsSuccessfull) return false; // how to determine all forms were successfull?
$.ajax({...});
})
};
let submitInlineForm = $form => {
return $.ajax({
url: $form.attr('action'),
type: 'post',
success: response => {
if (response.success) {
// ???????
// what to do here to indicate the inline form was successfully submitted?
} else {
// ???????
}
}
});
};
答案 0 :(得分:0)
很好的问题,也许不像最初看到的那么简单。
首先,您无需返回其他值和promise。
除非出现同步错误,否则表单提交成功/失败的全部内容都由submitInlineForm()
返回的诺言中传达了……。但是其中存在一些不足之处……
jQuery.ajax()
返回的承诺不是标准的。jQuery.when()
或Promise.all()
聚合的承诺中的任何单个失败都会(没有采取措施来阻止它)导致聚合的承诺采取其错误路径。...所以:
submitInlineForm()
返回的承诺,否则任何一次失败都会导致Promise.all()
返回的承诺失败。.then()
回调所暴露的多个参数。 幸运的是,有几个实用程序函数使主代码非常简单。
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+)
}));
};
有了这些实用程序,主代码就非常简单。
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'
});
};
未测试