Как предотвратить двойную форму отправки без потери каких-либо данных? - PullRequest
2 голосов
/ 11 февраля 2020

У меня есть форма HTML с двумя кнопками

<form action="...">
    ...
    <input type="submit" name="button1" value="Localized button 1">
    <input type="submit" name="button2" value="Otro botón">
<form>

и следующим JavaScript кодом

// prevent double submit and display a nice animation while submitting
$(document).on("submit", "form", function(event)
{
    $(this).find("input[type=submit], button").each(function()
    {
        var $button = $(this);
        $button.attr("disabled", "disabled");
        $button.addClass("submitting");
        setTimeout(function()
        {
            $button.removeAttr("disabled");
            $button.removeClass("submitting");
        }, 10000); // remove disabled status after timeout (ms)
    });
});

(плюс некоторые CSS переходы и анимации для создания .submitting выглядит красиво)

Приведенный выше код пытается предотвратить двойную отправку формы, потому что некоторые люди, похоже, неправильно понимают Интернет и продолжают дважды щелкать обычные кнопки отправки формы. У некоторых других людей есть проблемы с сенсорными экранами из-за рукопожатия или плохо работающих сломанных кнопок мыши, так что это тоже касается удобства использования.

Проблема в том, что Google Chrome запускает обработчик событий on("submit") до сбор данных для отправки вместе с отправкой формы. В результате правило HTML5 о том, что не отправляет входное значение, если его управление отключено, мешает и не позволяет включать любые кнопки отправки в запрос, который может видеть сервер. (Сервер ищет параметр button1 или button2, но игнорирует фактическое значение, потому что это локализованная строка из-за исторических HTML правил формы.)

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

Несколько недопустимых ссылок (пожалуйста, не отмечайте это как дубликат любой из них):

Дополнительные требования:

  • Разрешить повторную отправку формы после задержки (10 с c в приведенный выше пример), чтобы позволить пользователю обойти, например, прерванное сетевое соединение или сделать преднамеренную двойную передачу.
  • Нет быстрых решений (например, выполнение вышеуказанного кода с коротким таймаутом после фактического события on("submit") в надежде, что браузер собрал данные, но пользователь не достаточно быстр, чтобы дважды щелкнуть по кнопке.
  • Форма все еще должна работать с отключенным JavaScript - в этом случае нет возможности предотвратить двойную отправку формы.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2020

Вот реализация, которая кажется достаточно надежной для производственного использования:

    // prevent double submit and display a nice animation while submitting
    $(document).on("submit", "form", function(event)
    {
        $(this).find("input[type=submit], button").each(function()
        {
            var $button = $(this);

            if ($button.attr("disabled"))
                return; // this button is already disabled, do not touch it

            setTimeout(function()
            {
                $button.attr("disabled", "disabled");
                $button.addClass("submitting");
                setTimeout(function()
                {
                    $button.removeAttr("disabled");
                    $button.removeClass("submitting");
                }, 10000); // remove disabled status after timeout (ms)
            }, 0); // let the event loop run before disabling the buttons to allow form submission to collect form data (and emit "formdata" event) before disabling any buttons and hope that user is not fast enough to double submit before this happens
        });
    });

setTimeout(..., 0) - это хак, позволяющий Chrome запускать событие l oop один раз, чтобы получить Chrome собирать данные формы, прежде чем мы отключим кнопки, которые будут отбрасывать информацию о кнопке из представленных данных. Насколько я знаю, это не так уж плохо с пользовательским вводом, потому что здесь мы можем использовать задержку 0, и у пользователя нет возможности ввести любой ввод с нулевой задержкой.

0 голосов
/ 11 февраля 2020

Как насчет захвата клика с помощью onClick() и отправки формы перед отключением кнопок?

[не проверено]

$('input[type=submit]').click(function(e) {
    var $submitButton = $(e.target);

    // prevent automatic form submission
    e.preventDefault();

    // prevent double click without disabling
    if (! $submitButton.hasClass('submitting')) {
        $submitButton.addClass('submitting');

        // submit your form contents
        $('#your-form-id').submit();

        // disable all submit buttons
        $(this).find("input[type=submit], button").each(function()
        {
            var $button = $(this);
            $button.attr("disabled", "disabled");
            $button.addClass("submitting");
            setTimeout(function()
            {
                $button.removeAttr("disabled");
                $button.removeClass("submitting");
            }, 10000); // remove disabled status after timeout (ms)
        });
    }
});
...