Запретить двойную передачу форм в jQuery

У меня есть форма, которая занимает немного времени для обработки сервера. Мне нужно убедиться, что пользователь ждет и не пытается повторно отправить форму, снова нажав кнопку. Я попытался использовать следующий код jQuery:

<script type="text/javascript">
$(document).ready(function() {
    $("form#my_form").submit(function() {
        $('input').attr('disabled', 'disabled');
        $('a').attr('disabled', 'disabled');
        return true;
    });
});
</script>

Когда я пробую это в Firefox, все отключается, но форма не отправляется ни с одним из данных POST, которые предполагается включить. Я не могу использовать jQuery для отправки формы, потому что мне нужно, чтобы кнопка была отправлена ​​с формой, поскольку есть несколько кнопок отправки, и я определяю, какой из них был включен, в POST. Мне нужна форма для отправки, как обычно, и мне нужно отключить все сразу после этого.

Спасибо!

Ответ 1

Обновление в 2018 году: у меня есть несколько моментов для этого старого ответа, и я просто хотел добавить, что лучшим решением было бы сделать операцию idempotent, чтобы дублировать представления были безвредными.

Например, если форма создает заказ, поместите уникальный идентификатор в форму. В первый раз, когда сервер видит запрос создания заказа с этим идентификатором, он должен создать его и ответить "успехом". Последующие материалы также должны отвечать "успеху" (в случае, если клиент не получил первый ответ), но ничего не должен менять.

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


Я думаю, что ваша проблема в этой строке:

$('input').attr('disabled','disabled');

Вы отключите ВСЕ входные данные, в том числе, я думаю, те, чьи данные должны представить.

Чтобы отключить только кнопку отправки, вы можете сделать это:

$('button[type=submit], input[type=submit]').prop('disabled',true);

Однако я не думаю, что IE представит форму, если даже эти кнопки отключены. Я бы предложил другой подход.

Плагин jQuery для его решения

Мы просто решили эту проблему со следующим кодом. Трюк здесь использует data() jQuery data() чтобы отметить форму как уже представленную или нет. Таким образом, нам не нужно возиться с кнопками submit, которые вызывают IE.

// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
  $(this).on('submit',function(e){
    var $form = $(this);

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
    }
  });

  // Keep chainability
  return this;
};

Используйте его так:

$('form').preventDoubleSubmission();

Если есть AJAX формы, которые должны быть разрешено подавать несколько раз на странице загрузки, вы можете дать им класс, указывающий, что затем исключить их из своего выбора, как это:

$('form:not(.js-allow-double-submission)').preventDoubleSubmission();

Ответ 2

Временной подход неверен - как вы знаете, как долго действие будет выполняться в браузере клиента?

Как это сделать

$('form').submit(function(){
  $(this).find(':submit').attr('disabled','disabled');
});

Когда форма отправлена, она отключит все кнопки отправки внутри.

Помните, что в Firefox, когда вы отключите кнопку, это состояние будет запомнено, когда вы вернетесь в историю. Чтобы предотвратить, например, включение кнопок при загрузке страницы.

Ответ 3

Я думаю, что ответ Натана Лонга - это путь. Для меня я использую проверку на стороне клиента, поэтому я просто добавил условие, что форма будет действительной.

EDIT. Если это не добавлено, пользователь никогда не сможет отправить форму, если проверка на стороне клиента обнаруживает ошибку.

        // jQuery plugin to prevent double submission of forms
        jQuery.fn.preventDoubleSubmission = function () {
            $(this).on('submit', function (e) {
                var $form = $(this);

                if ($form.data('submitted') === true) {
                    // Previously submitted - don't submit again
                    alert('Form already submitted. Please wait.');
                    e.preventDefault();
                } else {
                    // Mark it so that the next submit can be ignored
                    // ADDED requirement that form be valid
                    if($form.valid()) {
                        $form.data('submitted', true);
                    }
                }
            });

            // Keep chainability
            return this;
        };

Ответ 4

event.timeStamp не работает в Firefox. Возвращение false нестандартно, вы должны вызвать event.preventDefault(). И пока мы на нем, всегда используют фигурные скобки с конструкцией управления.

Подводя итог всем предыдущим ответам, вот плагин, который выполняет задание и работает кросс-браузер.

jQuery.fn.preventDoubleSubmission = function() {

    var last_clicked, time_since_clicked;

    jQuery(this).bind('submit', function(event) {

        if(last_clicked) {
            time_since_clicked = jQuery.now() - last_clicked;
        }

        last_clicked = jQuery.now();

        if(time_since_clicked < 2000) {
            // Blocking form submit because it was too soon after the last submit.
            event.preventDefault();
        }

        return true;
    });
};

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

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

Ответ 5

Пожалуйста, ознакомьтесь с jquery-safeform плагином.

Пример использования:

$('.safeform').safeform({
    timeout: 5000,  // disable next submission for 5 sec
    submit: function() {
        // You can put validation and ajax stuff here...

        // When done no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
});

Ответ 6

... но форма не отправляется с любой из данных POST, которые предполагается включают в себя.

Правильно. Отключенные имена/значения элементов формы не будут отправляться на сервер. Вы должны установить их как элементы readonly.

Кроме того, привязки нельзя отключить так. Вам необходимо либо удалить их HREF (не рекомендуется), либо предотвратить их поведение по умолчанию (лучший способ), например:

<script type="text/javascript">
$(document).ready(function(){
    $("form#my_form").submit(function(){
      $('input').attr('readonly', true);
      $('input[type=submit]').attr("disabled", "disabled");
      $('a').unbind("click").click(function(e) {
          e.preventDefault();
          // or return false;
      });
    });
</script>

Ответ 7

Существует возможность улучшить подход Nathan Long . Вы можете заменить логику для обнаружения уже представленной формы следующим образом:

var lastTime = $(this).data("lastSubmitTime");
if (lastTime && typeof lastTime === "object") {
    var now = new Date();
    if ((now - lastTime) > 2000) // 2000ms
        return true;
    else
        return false;
}
$(this).data("lastSubmitTime", new Date());
return true; // or do an ajax call or smth else

Ответ 8

код Nathan, но для jQuery Validate plugin

Если вы используете плагин jQuery Validate, у них уже есть обработчик отправки, и в этом случае нет причин для внедрения более одного. Код:

jQuery.validator.setDefaults({
  submitHandler: function(form){
    // Prevent double submit
    if($(form).data('submitted')===true){
      // Previously submitted - don't submit again
      return false;
    } else {
      // Mark form as 'submitted' so that the next submit can be ignored
      $(form).data('submitted', true);
      return true;
    }
  }
});

Вы можете легко развернуть его в } else { -block, чтобы отключить входы и/или кнопку отправки.

Приветствия

Ответ 9

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

 jQuery.fn.preventDoubleSubmission = function() {

    var last_clicked, time_since_clicked;

    $(this).bind('submit', function(event){

    if(last_clicked) 
      time_since_clicked = event.timeStamp - last_clicked;

    last_clicked = event.timeStamp;

    if(time_since_clicked < 2000)
      return false;

    return true;
  });   
};

Используя следующее:

$('#my-form').preventDoubleSubmission();

Я обнаружил, что решения, которые не включали какой-то тайм-аут, а просто отключили подачу или отключили элементы формы, вызвали проблемы, потому что, как только блокировка запускается, вы не можете отправить ее снова, пока не обновите страницу. Это вызывает некоторые проблемы для меня при работе с ajax.

Возможно, это немного побалует, поскольку это не так уж и важно.

Ответ 10

Если вы используете AJAX для отправки формы, установите async: false, чтобы предотвратить дополнительные отправки до того, как форма очистится:

$("#form").submit(function(){
    var one = $("#one").val();
    var two = $("#two").val();
    $.ajax({
      type: "POST",
      async: false,  // <------ Will complete submit before allowing further action
      url: "process.php",
      data: "one="+one+"&two="+two+"&add=true",
      success: function(result){
        console.log(result);
        // do something with result
      },
      error: function(){alert('Error!')}
    });
    return false;
   }
});

Ответ 11

Модифицированное решение Nathan немного для Bootstrap 3. Это установит загружаемый текст в кнопку отправки. Кроме того, он истечет через 30 секунд и позволит повторно отправить форму.

jQuery.fn.preventDoubleSubmission = function() {
  $('input[type="submit"]').data('loading-text', 'Loading...');

  $(this).on('submit',function(e){
    var $form = $(this);

    $('input[type="submit"]', $form).button('loading');

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
      $form.setFormTimeout();
    }
  });

  // Keep chainability
  return this;
};

jQuery.fn.setFormTimeout = function() {
  var $form = $(this);
  setTimeout(function() {
    $('input[type="submit"]', $form).button('reset');
    alert('Form failed to submit within 30 seconds');
  }, 30000);
};

Ответ 12

Используйте две кнопки отправки.

<input id="sub" name="sub" type="submit" value="OK, Save">
<input id="sub2" name="sub2" type="submit" value="Hidden Submit" style="display:none">

И jQuery:

$("#sub").click(function(){
  $(this).val("Please wait..");
  $(this).attr("disabled","disabled");
  $("#sub2").click();
});

Ответ 13

У меня были похожие проблемы, и мои решения следующие.

Если у вас нет проверки на стороне клиента, вы можете просто использовать метод jquery one(), как описано здесь.

http://api.jquery.com/one/

Это отключает обработчик после его вызова.

$("#mysavebuttonid").on("click", function () {
  $('form').submit();
});

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

$("#mysavebuttonid").on("click", function (event) {
  $('form').submit();
  if (boolFormPassedClientSideValidation) {
        //form has passed client side validation and is going to be saved
        //now disable this button from future presses
        $(this).off(event);
   }
});

Ответ 14

вот как я это делаю:

$(document).ready(function () {
  $('.class_name').click(function () {
    $(this).parent().append('<img src="data:image/gif;base64,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" />');
    $(this).hide();
  });
});

кредиты: https://github.com/phpawy/jquery-submit-once

Ответ 15

этот код отобразит загрузку на ярлыке кнопки и установите кнопку

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

$(function () {

    $(".btn-Loading").each(function (idx, elm) {
        $(elm).click(function () {
            //do processing
            if ($(".input-validation-error").length > 0)
                return;
            $(this).attr("label", $(this).text()).text("loading ....");
            $(this).delay(1000).animate({ disabled: true }, 1000, function () {
                //original event call
                $.when($(elm).delay(1000).one("click")).done(function () {
                    $(this).animate({ disabled: false }, 1000, function () {
                        $(this).text($(this).attr("label"));
                    })
                });
                //processing finalized
            });
        });
    });
    // and fire it after definition
}

);

Ответ 16

Мое решение:

// jQuery plugin to prevent double submission of forms
$.fn.preventDoubleSubmission = function () {
    var $form = $(this);

    $form.find('[type="submit"]').click(function () {
        $(this).prop('disabled', true);
        $form.submit();
    });

    // Keep chainability
    return this;
};

Ответ 17

В моем случае форма onsubmit имела некоторый код проверки, поэтому я добавляю Nathan Long ответ, включая контрольную точку onsubmit

$.fn.preventDoubleSubmission = function() {
      $(this).on('submit',function(e){
        var $form = $(this);
        //if the form has something in onsubmit
        var submitCode = $form.attr('onsubmit');
        if(submitCode != undefined && submitCode != ''){
            var submitFunction = new Function (submitCode);
            if(!submitFunction()){
                event.preventDefault();
                return false;
            }                   
        }

        if ($form.data('submitted') === true) {
            /*Previously submitted - don't submit again */
            e.preventDefault();
        } else {
          /*Mark it so that the next submit can be ignored*/
          $form.data('submitted', true);
        }
      });

      /*Keep chainability*/
      return this;
    };

Ответ 18

Изменить кнопку отправки:

<input id="submitButtonId" type="submit" value="Delete" />

С обычной кнопкой:

<input id="submitButtonId" type="button" value="Delete" />

Затем используйте функцию щелчка:

$("#submitButtonId").click(function () {
        $('#submitButtonId').prop('disabled', true);
        $('#myForm').submit();
    });

И помните кнопку повторного включения, когда это необходимо:

$('#submitButtonId').prop('disabled', false);

Ответ 19

Используйте простой счетчик для отправки.

    var submitCounter = 0;
    function monitor() {
        submitCounter++;
        if (submitCounter < 2) {
            console.log('Submitted. Attempt: ' + submitCounter);
            return true;
        }
        console.log('Not Submitted. Attempt: ' + submitCounter);
        return false;
    }

И вызовите функцию monitor(), чтобы отправить форму.

    <form action="/someAction.go" onsubmit="return monitor();" method="POST">
        ....
        <input type="submit" value="Save Data">
    </form>

Ответ 20

Я не могу поверить в добрый старомодный трюк css из указателей-событий: никто еще не упоминался. У меня была такая же проблема, добавив отключенный атрибут, но это не сообщение. Попробуйте ниже и замените #SubmitButton на ID вашей кнопки отправки.

$(document).on('click', '#SubmitButton', function () {
    $(this).css('pointer-events', 'none');
})

Ответ 21

Почему бы не просто - это отправит форму, но также отключит кнопку отправки,

   $('#myForm').on('submit', function(e) {
       var clickedSubmit = $(this).find('input[type=submit]:focus');
       $(clickedSubmit).prop('disabled', true);
   });

Также, если вы используете jQuery Validate, вы можете поместить эти две строки в if ($('#myForm').valid()).

Ответ 22

Вы можете остановить вторую отправку этим

$("form").submit(function() {
        // submit more than once return false
        $(this).submit(function() {
            return false;
        });
        // submit once return true
        return true; // or do what you want to do
    });
});

Ответ 23

Я решил очень похожую проблему, используя:

$("#my_form").submit(function(){
    $('input[type=submit]').click(function(event){
        event.preventDefault();
    });
});