jQuery에서 양식의 이중 제출 방지


170

서버가 처리하는 데 시간이 조금 걸립니다. 버튼을 다시 클릭하여 사용자가 대기하고 양식을 다시 제출하지 않도록해야합니다. 다음 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 데이터와 함께 양식이 제출되지 않습니다. 제출 버튼이 여러 개 있으므로 양식과 함께 제출 해야하는 버튼이 필요하고 어느 값이 POST에 포함되어 있는지 결정했기 때문에 jQuery를 사용하여 양식을 제출할 수 없습니다. 일반적으로 양식을 제출해야하며 그 직후에 모든 것을 비활성화해야합니다.

감사!


모든 도움에 감사드립니다!
Adam

답변:


315

2018 년 업데이트 : 나는이 오래된 대답에 대한 몇 가지 요점을 얻었으며 최선의 해결책은 중복 제출이 무해하도록 작업을 dem 등원으로 만드는 것입니다.

예를 들어, 양식이 주문을 작성하는 경우 양식에 고유 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();

2
그냥 포인터 -이 캐시에 더 나은되지 않을 것 $(this)A를 var that = $(this)?
Stuart.Sklinar

5
@ Stuart.Sklinar-좋은 생각입니다. 나는 $form'설명'을 설명 $하기 때문에 사용했습니다. 제 규칙에 따르면 jQuery 객체이기 때문에 선행 을 사용했습니다.
Nathan Long

21
jquery를 사용할 때 눈에 띄지 않는 유효성 검사를 통해 양식이 유효한지 확인하는 것이 좋습니다. if ($ (this) .valid)) {$ form.data ( 'submitted', true);}
cck

1
@ cck 최고, 나는 그것을 사용했다. 내가 제거 한 여분의 닫는 paren이 있습니다. if ($ (this) .valid) {$ form.data ( 'submitted', true);
Brian MacKay

1
양식이 유효하지 않고 제출 버튼을 누르면 @BrianMacKay이 jquery 플러그인은 제출 된 속성을 true로 표시하지만 눈에 띄지 않는 유효성 검증은 유효성 검증 오류로 인한 제출을 막습니다. 제출 된 속성이 true이므로 오류를 정정 한 후 양식을 제출할 수 없습니다!
cck

44

타이밍 접근 방식이 잘못되었습니다. 클라이언트 브라우저에서 작업이 얼마나 오래 걸립니까?

그것을하는 방법

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

양식이 제출되면 내부의 모든 제출 버튼이 비활성화됩니다.

Firefox에서 버튼을 비활성화하면이 상태는 기록으로 돌아갈 때 기억됩니다. 예를 들어 페이지로드시 버튼을 활성화하지 않도록합니다.


2
파이어 폭스 팁으로 인해 +1이지만 페이지로드시 버튼을 활성화하는 것 외에 다른 옵션이 있습니까?
Raphael Isidro

1
가장 깨끗한 방법입니다. 클릭 이벤트 핸들러로 제출 버튼을 사용 중지하려고했지만 크롬에 문제가 발생했습니다. 이 솔루션은 아름답게 작동합니다.
앤서니

1
제출 단추에 값이 있고 필요한 경우 양식이 제출하지 않으므로이 방법에 매우주의하십시오.
Fabien Ménager

최신 jQuery 설명서에 따르면 .attr 대신 .prop를 사용해야합니다. 참조 : api.jquery.com/prop/#entry-longdesc-1 ".attr () 메소드 대신 .prop () 메소드를 사용하여 비활성화하고 확인하도록 설정해야합니다."
J Plana

19

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

9

event.timeStampFirefox에서는 작동하지 않습니다. 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을 해결하기 위해 제출 버튼을 두 번 클릭하려고 시도하지 않기 때문에 타이밍 방법이 효과적입니다. 제출에 대한 응답 시간이 매우 긴 경우 제출 단추 또는 양식을 스피너로 바꾸는 것이 좋습니다.

위의 예에서와 같이 양식의 후속 제출을 완전히 차단하면 부작용이 하나 있습니다. 만든. 이것은 분명히 화난 사용자가 될 것입니다.


2
네가 옳아. 다른 방법으로 갈 수 있습니다-즉시 비활성화 한 다음 오랜 시간이 지나면 다시 활성화하십시오. 두 번 클릭을 방지하고 다시 제출할 수 있지만 지연된 사용자에 대해 유효하지 않은 다시 제출을 허용합니다.
Ctrl-C

8

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

4

...하지만 양식은 포함해야 할 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>

@Adam, 예. 첨부 된 클릭 핸들러가 실행됩니다. 나는 당신이 그것들이 수정되는 것을 막고 싶었다고 생각 했습니까?
karim79

@ karim79 클릭 핸들러가 실행되는지 상관하지 않습니다. 사용자가 다른 제출 버튼을 클릭하여 양식이 다시 제출되지 않도록하고 싶습니다.
Adam

@ 아담-아니, 그런 일은 일어나지 않을 것입니다. 예를 들어 추가 $('input[type=submit]').attr("disabled", "disabled");했지만 가장 좋아하는 방법은 onclick="this.disabled = 'disabled'"제출의 onclick 에 넣는 것입니다 .
karim79

@ karim79 나는 그것을 시도했지만 클릭 한 제출 버튼은 POST에 포함되어 있지 않습니다. 클릭 한 버튼을 확인하려면 POST에 포함시켜야합니다.
Adam

'a'에 대한 클릭 이벤트를 금지했지만 $ ( 'a'). click (function (e) {e.preventDefault (); // 또는 return false;}); ?
Fabio

4

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

1
지구상에서 왜이 접근법에 타이머를 사용 하시겠습니까?
Bobort

4

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 내에서 쉽게 확장하여 입력 및 / 또는 제출 버튼을 비활성화 할 수 있습니다 .

건배


2

이 게시물의 아이디어를 사용하여 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();

잠금이 트리거되면 페이지를 새로 고칠 때까지 다시 제출 할 수 없기 때문에 일종의 시간 초과가 포함되지 않았지만 제출을 비활성화하거나 양식 요소를 비활성화 한 솔루션이 문제를 일으킨다는 것을 알았습니다. 아약스 작업을 할 때 문제가 발생합니다.

이것은 아마도 그 공상이 아닌 것처럼 조금 예쁘게 보일 수 있습니다.


2

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

3
<code> asnyc : true </ code> 설정은 요청이 완료 될 때까지 브라우저를 정지시켜 AJAX의 본질을 능가하는 브라우저를 정지시키기 때문에 잘못된 접근입니다
Edwin M

2

부트 스트랩 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);
};

2

두 개의 제출 단추를 사용하십시오.

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

2

제출시 간단한 카운터를 사용하십시오.

    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>

1

비슷한 문제가 발생했으며 솔루션은 다음과 같습니다.

클라이언트 측 유효성 검사가 없으면 여기에 설명 된대로 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);
   }
});

1

이것으로 두 번째 제출을 중지 할 수 있습니다

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

0

내 해결책 :

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

0

제 경우에는 양식의 onsubmit에 유효성 검사 코드가 있으므로 onsubmit 검사 점을 포함하여 Nathan Long 응답을 증가시킵니다.

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

0

제출 변경 버튼 :

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

0

포인터 이벤트의 구식 CSS 트릭을 믿을 수 없습니다. 아직 언급되지 않은 곳입니다. 비활성화 된 속성을 추가하여 동일한 문제가 발생했지만 다시 게시되지 않습니다. 아래를 시도하고 #SubmitButton을 제출 버튼의 ID로 바꾸십시오.

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

사용자가 Enter키를 누르면 양식 제출이 중지되지 않습니다 .
개혁

0

이뿐 만 아니라 양식을 제출할뿐 아니라 제출 버튼도 사용 중지합니다.

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

또한 jQuery Validate를 사용하는 경우이 두 줄을 아래에 넣을 수 있습니다 if ($('#myForm').valid()).


0

이 코드는 버튼 라벨에 로딩을 표시하고 버튼을

비활성화 상태, 처리 후 원래 버튼 텍스트 **를 다시 활성화하고 다시 반환 **

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

-1

나는 다음을 사용하여 매우 비슷한 문제를 해결했다.

$("#my_form").submit(function(){
    $('input[type=submit]').click(function(event){
        event.preventDefault();
    });
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.