Éviter la double soumission des formulaires en jQuery
j'ai un formulaire qui prend un peu de temps pour le serveur. Je dois m'assurer que l'utilisateur attend et ne tente pas de soumettre à nouveau le formulaire en cliquant de nouveau sur le bouton. J'ai essayé d'utiliser le code jQuery suivant:
<script type="text/javascript">
$(document).ready(function() {
$("form#my_form").submit(function() {
$('input').attr('disabled', 'disabled');
$('a').attr('disabled', 'disabled');
return true;
});
});
</script>
quand J'essaie cela dans Firefox, tout est désactivé mais le formulaire n'est pas soumis avec les données POST qu'il est censé inclure. Je ne peux pas utiliser jQuery pour soumettre le formulaire parce que j'ai besoin que le bouton soit soumis avec le forme puisqu'il y a plusieurs boutons de soumission et je déterminer qui a été utilisée par lequel la valeur est incluse dans le POSTE. J'ai besoin que le formulaire soit soumis tel qu'il est habituellement et j'ai besoin de tout désactiver juste après que cela arrive.
Merci!
20 réponses
je pense que votre problème est cette ligne:
$('input').attr('disabled','disabled');
vous désactivez toutes les entrées, y compris, je suppose, celles dont les données que le formulaire est censé soumettre.
pour désactiver juste le(S) bouton (s) soumettre, vous pourrait faire ceci:
$('button[type=submit], input[type=submit]').prop('disabled',true);
cependant, je ne pense pas QU'IE soumettra le formulaire si même ces boutons sont désactivés. Je suggère une autre approche.
un plugin jQuery pour le résoudre
nous venons de résoudre ce problème avec le code suivant. L'astuce ici est d'utiliser le data()
de jQuery pour marquer le formulaire comme déjà soumis ou non. Comme ça, on n'a pas à jouer avec les boutons soumettre, ce qui fait flipper.
// 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;
};
utilisez - le comme ceci:
$('form').preventDoubleSubmission();
S'il y a des formulaires AJAX que devrait devrait être autorisé à soumettre plusieurs fois par page load, vous pouvez leur donner une classe indiquant que, puis les exclure de votre sélecteur comme ceci:
$('form:not(.js-allow-double-submission)').preventDoubleSubmission();
L'approche temporelle est erronée-comment savez-vous combien de temps l'action prendra sur le navigateur du client?
Comment faire
$('form').submit(function(){
$(this).find(':submit').attr('disabled','disabled');
});
lorsque le formulaire est soumis, il désactivera tous les boutons soumettre à l'intérieur.
rappelez-vous, dans Firefox quand vous désactivez un bouton cet état sera rappelé lorsque vous retournez dans l'histoire. Pour éviter cela, vous devez activer les boutons sur la page de chargement, par exemple.
je pense que la réponse de Nathan Long est la voie à suivre. Pour moi, j'utilise la validation côté client, donc j'ai juste ajouté une condition que le formulaire soit valide.
EDIT : Si ceci n'est pas ajouté, l'utilisateur ne pourra jamais soumettre le formulaire si la validation côté client rencontre une erreur.
// 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
ne fonctionne pas dans Firefox. Retourner false n'est pas standard, vous devez appeler event.preventDefault()
. Et pendant que nous y sommes, "toujours utilisez des entretoises avec une construction de contrôle .
pour résumer toutes les réponses précédentes, voici un plugin qui fait le travail et fonctionne cross-browser.
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;
});
};
pour adresser Kern3l, la méthode de chronométrage fonctionne pour moi tout simplement parce que nous essayons d'arrêter un double-cliquez sur le bouton "soumettre". Si vous avez un très long délai de réponse à une soumission, je vous recommande de remplacer le bouton Soumettre ou le formulaire par une broche.
le fait de bloquer complètement les soumissions subséquentes du formulaire, comme le font la plupart des exemples ci-dessus, a un mauvais effet secondaire: s'il y a une défaillance du réseau et qu'ils veulent essayer de soumettre de nouveau, ils ne seraient pas en mesure de le faire et perdraient les changements qu'ils ont faits. Cela ferait certainement un utilisateur en colère.
s'il vous Plaît, consultez jquery-safeform plugin.
exemple d'utilisation:
$('.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;
}
});
...mais le formulaire n'est pas soumis à toutes les données POST qu'il est censé comprendre.
Correct. Les noms/valeurs d'éléments de formulaire désactivés ne seront pas envoyés au serveur. Vous devez les définir comme readonly éléments.
aussi, les ancres ne peuvent pas être désactivées comme ça. Vous aurez besoin soit de supprimer leurs href (non recommandé) ou d'empêcher leur comportement par défaut( meilleure façon), par exemple:
<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>
il est possible d'améliorer L'approche de Nathan Long . Vous pouvez remplacer la logique de détection du formulaire déjà soumis par celle-ci:
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
code de Nathan mais pour jQuery valider plugin
si vous utilisez jQuery Validate plugin, ils ont déjà submit handler implémenté, et dans ce cas il n'y a aucune raison d'implémenter plus d'un plugin. Le code:
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;
}
}
});
vous pouvez facilement l'étendre dans le bloc } else {
- pour désactiver les entrées et/ou soumettre le bouton.
Cheers
j'ai fini par utiliser les idées de ce post pour trouver une solution qui est assez similaire à la version D'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;
});
};
en utilisant comme ceci:
$('#my-form').preventDoubleSubmission();
j'ai trouvé que les solutions qui n'incluaient pas une sorte de timeout mais juste une soumission désactivée ou des éléments de formulaire désactivés ont causé des problèmes parce qu'une fois le lock-out déclenché vous ne pouvez pas soumettre à nouveau jusqu'à ce que vous rafraîchissez la page. Cela me pose des problèmes quand je fais des trucs ajax.
cela peut probablement être mis en place un peu comme il n'est pas si fantaisiste.
si vous utilisez AJAX pour afficher un formulaire, mettez async: false
devrait empêcher les soumissions supplémentaires avant que le formulaire se dégage:
$("#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;
}
});
a modifié un peu la solution de Nathan pour Bootstrap 3. Cela va définir un texte de chargement sur le bouton Soumettre. De plus, il sera temporisé après 30 secondes et permettra au formulaire d'être soumis à nouveau.
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);
};
utilisez deux boutons soumettre.
<input id="sub" name="sub" type="submit" value="OK, Save">
<input id="sub2" name="sub2" type="submit" value="Hidden Submit" style="display:none">
et jQuery:
$("#sub").click(function(){
$(this).val("Please wait..");
$(this).attr("disabled","disabled");
$("#sub2").click();
});
j'ai eu des problèmes similaires et ma ou mes solutions sont les suivantes.
si vous n'avez pas de validation côté client, alors vous pouvez simplement utiliser la méthode jquery one() comme documentée ici.
ceci désactive le handler après qu'il ait été invoqué.
$("#mysavebuttonid").on("click", function () {
$('form').submit();
});
si vous faites la validation côté client comme je le faisais alors c'est un peu plus délicat. L'exemple ci-dessus ne vous permettrait pas de soumettre à nouveau après un échec de la validation. Essayez plutôt cette approche
$("#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);
}
});
voici comment je fais:
$(document).ready(function () {
$('.class_name').click(function () {
$(this).parent().append('<img src="data:image/gif;base64,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" />');
$(this).hide();
});
});
ce code affichera le chargement sur l'étiquette du bouton, et le bouton de réglage à
désactivation de l'état, puis, après traitement, de le ré-activer et retourner l'original du texte du bouton**
$(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
}
);
ma solution:
// 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;
};
dans mon cas, l'onsubmit du formulaire avait un code de validation, donc je incrémente Nathan Long réponse incluant un point de contrôle de l'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;
};
modifier le bouton Soumettre:
<input id="submitButtonId" type="submit" value="Delete" />
avec le bouton normal:
<input id="submitButtonId" type="button" value="Delete" />
puis utiliser la fonction de clic:
$("#submitButtonId").click(function () {
$('#submitButtonId').prop('disabled', true);
$('#myForm').submit();
});
et n'oubliez pas le bouton re-enable quand il est nécessaire:
$('#submitButtonId').prop('disabled', false);
Utilisation simple compteur sur "soumettre".
var submitCounter = 0;
function monitor() {
submitCounter++;
if (submitCounter < 2) {
console.log('Submitted. Attempt: ' + submitCounter);
return true;
}
console.log('Not Submitted. Attempt: ' + submitCounter);
return false;
}
et appeler la fonction monitor()
sur soumettre le formulaire.
<form action="/someAction.go" onsubmit="return monitor();" method="POST">
....
<input type="submit" value="Save Data">
</form>
j'ai résolu un problème très similaire en utilisant:
$("#my_form").submit(function(){
$('input[type=submit]').click(function(event){
event.preventDefault();
});
});