Предотвращение двойной отправки форм в 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 для отправки формы, потому что мне нужна кнопка для отправки с формой, как есть несколько кнопок отправки, и я определяю, что было использовано, какое значение Включено в сообщение. Мне нужно, чтобы форма была отправлена, как обычно, и мне нужно отключить все сразу после этого.

спасибо!

20 139

20 ответов:

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

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

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

чтобы отключить только кнопку(ы) отправки, вы может этого:

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

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

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

мы просто решена эта проблема с помощью следующего кода. Трюк здесь заключается в использовании jQuery data() пометить форму как уже отправленную или нет. Таким образом, нам не нужно возиться с кнопками отправки, что уродует 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();

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

как это делается

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

при отправке формы он отключит все кнопки отправки внутри.

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

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

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

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, метод синхронизации работает для меня просто потому, что мы пытаемся остановить двойной щелчок кнопки отправки. Если у вас есть очень долго время отклика на отправку, я рекомендую заменить кнопку отправки или форму с прядильщиком.

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

пожалуйста, проверьте 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;
    }
});

...но форма не представляется с любые данные POST, которые он должен включать.

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

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

<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>

есть возможность улучшить Натана Лонга подход. Вы можете заменить логику для обнаружения уже отправленной формы на эту:

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

код Натана, но для 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 {-блок для отключения входов и/или кнопку "Отправить".

Ура

Я закончил тем, что использовал идеи из этого поста, чтобы придумать решение, которое очень похоже на версию 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.

этот вероятно, можно немного приукрасить, так как это не так уж и причудливо.

при использовании 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;
   }
});

немного изменил решение Натана для 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);
};

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

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

у меня были подобные проблемы, и мое решение(ы) выглядит следующим образом.

Если у вас нет никакой проверки на стороне клиента, то вы можете просто использовать метод 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);
   }
});

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

$(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

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

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

$(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
}

);

мое решение:

// 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;
};

в моем случае форма onsubmit имела некоторый код проверки, поэтому я увеличиваю Натан Лонг ответ, включая контрольную точку 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;
    };

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

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

использовать простой счетчик на Отправить.

    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>

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

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