Вернуть дополнительные значения вместе с обещанием - PullRequest
0 голосов
/ 24 января 2020

У меня есть основная форма и несколько связанных встроенных форм. При отправке основной формы все остальные встроенные формы должны быть отправлены вместе.

Однако, если какая-либо из встроенных форм не удалась (мы отмечаем ее в ответе), основная форма не будет суммирована.

Проблема в том, что 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 {
                // ???????
            }
        }
    });
};

1 Ответ

0 голосов
/ 25 января 2020

Хороший вопрос, и, возможно, не такой простой, как кажется на первый взгляд.

Во-первых, вам не нужно возвращать дополнительные значения вместе с обещанием.

Запрет на синхронные ошибки, полностью об успехе / неудаче отправки формы передается в обещании, возвращаемом submitInlineForm() .... но в этом есть ошибки ...

  • обещания, возвращаемые jQuery.ajax(), не являются стандартными.
  • Любой отдельный сбой в наборе обещаний, агрегированных с jQuery.when() или Promise.all(), приведет (без мер по предотвращению) к агрегированному обещанию, выбравшему путь ошибки.

... так:

  • для подсчета успехов и неудач вы можете отразить обещания, возвращенные submitInlineForm(), в противном случае любой отдельный сбой вызовет обещание, возвращенное Promise.all() сбой.
  • Для успешного отражения jqXHR (стандартным способом) необходимо сначала нормализовать множественные параметры, подвергаемые обратным вызовам .then() jqXHR.

К счастью, пара служебных функций позволяет основному коду быть довольно простым.

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'
    });
};

не проверено

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...