簡體   English   中英

防止在 jQuery 中重復提交表單

[英]Prevent double submission of forms in 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 中包含哪個值。 我需要像往常一樣提交表單,並且我需要在發生這種情況后立即禁用所有內容。

謝謝!

2018 年更新:我剛剛從這個舊答案中得到了一些分數,只是想補充一點,最好的解決方案是使操作具有冪等性,以便重復提交是無害的。

例如,如果表單創建了一個訂單,則在表單中放置一個唯一的 ID。 服務器第一次看到帶有該 id 的訂單創建請求時,它應該創建它並響應“成功”。 隨后的提交也應該響應“成功”(以防客戶沒有得到第一個響應)但不應該改變任何東西。

應通過數據庫中的唯一性檢查來檢測重復項,以防止出現競爭條件。


我認為你的問題是這一行:

$('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 中,當您禁用按鈕時,該狀態將在您返回歷史記錄時被記住。 例如,為了防止您必須在頁面加載時啟用按鈕。

我認為 Nathan Long 的答案是要走的路。 對我來說,我使用的是客戶端驗證,所以我只是添加了表單有效的條件。

編輯:如果沒有添加,如果客戶端驗證遇到錯誤,用戶將永遠無法提交表單。

        // 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 數據。

正確的。 禁用的表單元素名稱/值將不會發送到服務器。 您應該將它們設置為只讀元素。

此外,錨不能像那樣被禁用。 您將需要刪除他們的 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>

Nathan 的代碼,但用於 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 { -block 中輕松擴展它以禁用輸入和/或提交按鈕。

干杯

有可能改進 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

我最終使用這篇文章中的想法提出了一個與 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 稍微修改了 Nathan 的解決方案。這將為提交按鈕設置加載文本。 此外,它將在 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();
});

在提交時使用簡單的計數器。

    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>

我一直有類似的問題,我的解決方案如下。

如果您沒有任何客戶端驗證,那么您可以簡單地使用此處記錄的 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

您可以通過此停止第二次提交

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

只要您不導入 jQuery 驗證插件,所有這些解決方案都可以通過。

例如,如果客戶端輸入無效輸入並提交表單,則無論 jQuery 驗證是否檢測到無效輸入,按鈕都會被禁用。 然后客戶將無法在修復他們的輸入后重新提交表單。

此問題的解決方法只需要一個 if 語句:

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

將此代碼添加到我全局導入的 JavaScript 文件后,我嘗試在我的網站上重復發布表單失敗。

此代碼將在按鈕標簽上顯示加載,並將按鈕設置為

禁用狀態,然后處理后,重新啟用並返回原始按鈕文本**

$(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 有一些驗證代碼,所以我增加了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;
    };

更改提交按鈕:

<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 替換為您提交按鈕的 ID。

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

我使用以下方法解決了一個非常相似的問題:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM