Вопрос

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

Спасибо!

Это было полезно?

Решение

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

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

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


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

$('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, когда вы отключаете кнопку, это состояние будет запомнено, когда вы вернетесь в историю.Чтобы предотвратить это, вам нужно, например, включить кнопки при загрузке страницы.

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

РЕДАКТИРОВАТЬ:Если это не добавлено, пользователь никогда не сможет отправить форму, если проверка на стороне клиента обнаружит ошибку.

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

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

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

Кроме того, якоря нельзя отключить таким образом.Вам нужно будет либо удалить их 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>

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

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

Если вы используете плагин 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.

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

Если вы используете АЯКС чтобы опубликовать форму, установите 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

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

    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>

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

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

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

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

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

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

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

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

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

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

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

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

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

$("#my_form").submit(function(){
    $('input[type=submit]').click(function(event){
        event.preventDefault();
    });
});
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top