Запретить двойную отправку форм в 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. Мне нужно отправить форму, как обычно, и мне нужно отключить все сразу после того, как это произойдет.
Спасибо!
25 ответов
Обновление в 2018 году: я только что получил несколько баллов за этот старый ответ и просто хотел добавить, что лучшим решением было бы сделать операцию идемпотентной, чтобы дублирующие представления были безвредными.
Например, если форма создает заказ, укажите уникальный идентификатор в форме. Когда сервер впервые видит запрос на создание заказа с этим идентификатором, он должен создать его и ответить "успех". Последующие представления также должны отвечать "успех" (в случае, если клиент не получил первый ответ), но не должны ничего менять.
Дубликаты должны быть обнаружены с помощью проверки уникальности в базе данных, чтобы предотвратить состояние гонки.
Я думаю, что ваша проблема в этой строке:
$('input').attr('disabled','disabled');
Вы отключаете ВСЕ входные данные, в том числе, я полагаю, те, чьи данные должна предоставить форма.
Чтобы отключить только кнопку отправки, вы можете сделать это:
$('button[type=submit], input[type=submit]').prop('disabled',true);
Тем не менее, я не думаю, что IE отправит форму, даже если эти кнопки отключены. Я бы предложил другой подход.
Плагин JQuery, чтобы решить это
Мы только что решили эту проблему с помощью следующего кода. Хитрость здесь заключается в использовании jQuery's 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;
}
});
... но форма не отправлена с данными 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>
Код Натана, но для плагина 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 {
-Блок для отключения входов и / или кнопку отправки.
ура
Есть возможность улучшить подход Натана Лонга. Вы можете заменить логику обнаружения уже отправленной формы этой:
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
Вы можете остановить вторую отправку этим
$("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
});
});
Я закончил тем, что использовал идеи из этого поста, чтобы найти решение, очень похожее на версию 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.
Это, вероятно, можно немного приукрашивать, так как это не так уж и красиво.
Немного изменил решение Натана для 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);
};
Используйте простой счетчик при отправке.
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>
Используйте две кнопки отправки.
<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();
});
Если вы используете 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;
}
});
Вот как я это делаю:
$(document).ready(function () {
$('.class_name').click(function () {
$(this).parent().append('<img src="data:image/gif;base64,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" />');
$(this).hide();
});
});
У меня были подобные проблемы, и мои решения следующие.
Если у вас нет какой-либо проверки на стороне клиента, вы можете просто использовать метод jquery 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);
}
});
Все эти решения приемлемы до тех пор, пока вы не импортируете плагин проверки jQuery.
Например, если клиент вводит недопустимый ввод и отправляет форму, кнопка будет отключена независимо от того, обнаруживает ли проверка jQuery недопустимый ввод. Тогда клиент не сможет повторно отправить форму после исправления своего ввода.
Обходной путь для этой проблемы потребовал только одного оператора if:
$('form').submit(function () {
if ($(this).valid()) {
$(this).find("input[type='submit']").prop('disabled', true);
}
});
После добавления этого кода в мой глобально импортированный файл JavaScript мне не удалось дважды разместить формы на моем веб-сайте.
Изменить кнопку отправки:
<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);
В моем случае на отправке формы был некоторый проверочный код, поэтому я увеличиваю ответ 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;
};
Я не могу поверить старому доброму уловке 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())
,
Самый лучший способ, который я нашел, - это сразу отключить кнопку при нажатии:
$('#myButton').click(function() {
$('#myButton').prop('disabled', true);
});
И снова включите его при необходимости, например:
- проверка не удалась
- ошибка при обработке данных формы сервером, затем после ответа об ошибке с помощью jQuery
Этот код будет отображать загрузку на ярлыке кнопки и установить кнопку в
отключить состояние, затем после обработки снова включить и вернуть исходный текст кнопки **
$(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;
};
Я решил очень похожую проблему, используя:
$("#my_form").submit(function(){
$('input[type=submit]').click(function(event){
event.preventDefault();
});
});