Comment empêcher le formulaire de se soumettre plusieurs fois du côté client?

96

Parfois, lorsque la réponse est lente, on peut cliquer plusieurs fois sur le bouton Soumettre.

Comment éviter que cela ne se produise?

OMG
la source
4
J'espère que la raison pour laquelle vous mettez «côté client» sur le titre de votre question est parce que vous savez que toute solution du client pour essayer d'éviter les soumissions de dupe est 100% non sécurisée et vous devriez toujours faire la validation côté serveur.
Paolo Bergantino
51
Paolo: Oui, si vous êtes intéressé par la sécurité complète des données, cela devrait être fait côté serveur. Mais parfois, vous voulez simplement empêcher grand-mère de double-cliquer sur le bouton Soumettre alors qu'il ne nécessite qu'un seul clic. Dans ces cas, javascript convient parfaitement.
Simon East
1
Le faire uniquement côté serveur n'est pas non plus sûr à 100%, car votre première requête peut prendre suffisamment de temps pour se terminer pour que la seconde sache qu'elle ne devrait pas continuer.
igorsantos07
Le modèle de cookie à double soumission pour empêcher les attaques CSRF n'empêche- t-il pas également la soumission de formulaires multiples?
Martin Thoma

Réponses:

99

Utilisez un javascript discret pour désactiver l'événement d'envoi sur le formulaire après qu'il a déjà été soumis. Voici un exemple utilisant jQuery.

MODIFIER: Correction d'un problème avec la soumission d'un formulaire sans cliquer sur le bouton Soumettre. Merci, ichiban.

$("body").on("submit", "form", function() {
    $(this).submit(function() {
        return false;
    });
    return true;
});
Starx
la source
4
Que faire si le formulaire est soumis en appuyant sur Entrée dans une zone de texte?
ichiban
2
Avez-vous même besoin du return true? Je pense que la soumission initiale devrait fonctionner sans cela.
Simon East
Je crois que le return trueest implicite s'il est omis.
Derek
15
J'ai essayé cette solution avec une validation discrète et MVC. Le JS est d'abord appelé, ce qui renvoie toujours false, puis la validation est appelée. Donc, si mon formulaire a une erreur de validation, le formulaire n'est jamais soumis !!
bjan
6
fonctionne vraiment très bien. J'aime également désactiver le bouton d'envoi et remplacer le texte du bouton d'envoi pour afficher également l'indication de l'utilisateur. $(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
Cam Song
42

J'ai essayé la solution de vanstee avec la validation discrète d'asp mvc 3, et si la validation du client échoue, le code est toujours exécuté et la soumission du formulaire est désactivée pour de bon. Je ne peux pas soumettre à nouveau après avoir corrigé les champs. (voir le commentaire de bjan)

J'ai donc modifié le script de vanstee comme ceci:

$("form").submit(function () {
    if ($(this).valid()) {
        $(this).submit(function () {
            return false;
        });
        return true;
    }
    else {
        return false;
    }
});
m irina
la source
Y a-t-il d'autres effets secondaires à noter, ou cela a-t-il fonctionné pour que vous puissiez les appliquer partout?
Ciaran Gallagher le
24

Le contrôle de soumission de formulaire côté client peut être obtenu de manière assez élégante en demandant au gestionnaire onsubmit de masquer le bouton d'envoi et de le remplacer par une animation de chargement. De cette façon, l'utilisateur obtient un retour visuel immédiat au même endroit où son action (le clic) s'est produite. Dans le même temps, vous empêchez le formulaire d'être soumis une autre fois.

Si vous soumettez le formulaire via XHR, gardez à l'esprit que vous devez également gérer les erreurs de soumission, par exemple un délai d'expiration. Vous devrez à nouveau afficher le bouton d'envoi car l'utilisateur doit resoumettre le formulaire.

Sur une autre note, llimllib soulève un point très valable. Toute validation de formulaire doit avoir lieu côté serveur. Cela comprend plusieurs contrôles de soumission. Ne faites jamais confiance au client! Ce n'est pas seulement un cas si javascript est désactivé. Vous devez garder à l'esprit que tout le code côté client peut être modifié. C'est un peu difficile à imaginer mais le html / javascript qui parle à votre serveur n'est pas forcément le html / javascript que vous avez écrit.

Comme le suggère llimllib, générez le formulaire avec un identifiant unique pour ce formulaire et placez-le dans un champ de saisie masqué. Stockez cet identifiant. Lors de la réception des données du formulaire, ne les traitez que lorsque l'identifiant correspond. (Lier également l'identifiant à la session des utilisateurs et faire correspondre cela également pour plus de sécurité.) Après le traitement des données, supprimez l'identifiant.

Bien sûr, de temps en temps, vous devrez nettoyer les identifiants pour lesquels aucune donnée de formulaire n'a été soumise. Mais très probablement, votre site Web utilise déjà une sorte de mécanisme de «ramassage des ordures».

Rob
la source
15
<form onsubmit="if(submitted) return false; submitted = true; return true">
le chaos
la source
6
Utilisez <form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">, ou écrire var submitted = false;au bon moment de votre script, pour éviter l'erreur suivante: Uncaught ReferenceError: submitted is not defined.
Tamás Bolvári
15

Voici un moyen simple de le faire:

<form onsubmit="return checkBeforeSubmit()">
  some input:<input type="text">
  <input type="submit" value="submit" />
</form>

<script type="text/javascript">
  var wasSubmitted = false;    
    function checkBeforeSubmit(){
      if(!wasSubmitted) {
        wasSubmitted = true;
        return wasSubmitted;
      }
      return false;
    }    
</script>
ichiban
la source
avec la validation discrète de jQuery, le script de blocage est appelé en premier et la validation ensuite, ce qui n'entraîne aucune soumission du tout s'il y a des erreurs de validation
bjan
8

Désactivez le bouton d'envoi peu de temps après un clic. Assurez-vous de gérer correctement les validations. Conservez également une page intermédiaire pour tous les traitements ou opérations DB, puis redirigez vers la page suivante. Cela garantit que l'actualisation de la deuxième page n'effectue pas un autre traitement.

Shoban
la source
Ouais, bon conseil Shoban, je suis d'accord. Devrait êtreform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
Simon East
6

Hash l'heure actuelle, en faire une entrée masquée sur le formulaire. Du côté du serveur, vérifiez le hachage de chaque soumission de formulaire; si vous avez déjà reçu ce hachage, vous avez une soumission répétée.

edit: s'appuyer sur javascript n'est pas une bonne idée, vous pouvez donc tous continuer à voter pour ces idées, mais certains utilisateurs ne l'activeront pas. La bonne réponse est de ne pas faire confiance aux entrées de l'utilisateur côté serveur.

llimllib
la source
Est-ce que ça n'a pas l'air "Trop"? ;-)
Shoban
1
Cela semble empêcher un utilisateur de soumettre le formulaire plus d'une fois par seconde. Si je soumets le formulaire à 2009-05-29 12:13:37, le serveur ne me laissera pas soumettre un autre formulaire avec le même hachage, mais si j'ai cliqué sur Soumettre à 2009-05-29 12:13:38, cela passerait. De plus, votre technique empêcherait 2 utilisateurs différents de soumettre simultanément deux formulaires différents: l'un d'entre eux serait expulsé, même s'il s'agissait probablement de la première soumission de sa part.
Sarah Vessels
2
@moneypenny votre première objection est fausse, le hachage correspondrait à l'heure à laquelle le formulaire a été envoyé à l'utilisateur, pas à l'heure à laquelle il a été soumis. Si vous êtes vraiment inquiet pour le second, vous avez beaucoup d'options. Ajoutez leur identifiant de session à la chaîne que vous avez hachée et / ou vérifiez tous les champs du formulaire pour la similitude exacte; deux utilisateurs n'ont probablement pas soumis exactement le même formulaire.
llimllib
@Shoban Je suis désolé, je ne suis pas ce que vous dites
llimllib
2
«Excessif» est dans l'œil du spectateur. Si vous avez vraiment besoin d'éviter les soumissions de formulaires en double, au moins une partie de la solution doit être côté serveur. "Vous ne pouvez pas faire confiance aux utilisateurs."
Ben Blank
5

Vous pouvez également afficher une barre de progression ou une double flèche pour indiquer que le formulaire est en cours de traitement.

Tony Borf
la source
5

En utilisant JQuery, vous pouvez faire:

$('input:submit').click( function() { this.disabled = true } );

&

   $('input:submit').keypress( function(e) {
     if (e.which == 13) {
        this.disabled = true 
     } 
    }
   );
Boris Guéry
la source
1
Que faire si le formulaire est soumis en appuyant sur ENTRÉE dans une zone de texte après la désactivation du bouton?
ichiban
Désactiver le bouton comme ceci empêchera l'utilisateur d'appuyer sur ENTRÉE. Mais, à droite, il faut lier une touche sur l'entrée de soumission
Boris Guéry
Cela empêche le bouton de soumettre. Par conséquent, désactivation de la validation côté serveur.
Marko Aleksić
@Marko, d'accord, mais c'est l'OP demandé, de toute façon utiliser un jeton empêcherait le formulaire de se soumettre deux fois.
Boris Guéry
1
Lorsque j'ai essayé ce type de technique, j'ai constaté que le formulaire ne se soumettait pas du tout (du moins pas dans Chrome 14), probablement parce que vous désactivez le bouton avant que le navigateur ne lance la soumission du formulaire.
Simon East
4

Je sais que vous avez tagué votre question avec 'javascript', mais voici une solution qui ne dépend pas du tout de javascript:

C'est un modèle d'application Web nommé PRG , et voici un bon article qui le décrit

Pablo Fernandez
la source
4

Vous pouvez empêcher l'envoi multiple simplement avec:

var Workin = false;

$('form').submit(function()
{
   if(Workin) return false;
   Workin =true;

   // codes here.
   // Once you finish turn the Workin variable into false 
   // to enable the submit event again
   Workin = false;

});
Alpha
la source
Le problème avec votre réponse est qu'il y a une fraction de seconde entre le moment où l'utilisateur clique et l'heure Workin =true;. Les soumissions doubles sont toujours possibles, mais moins sont probables.
sent1nel
4

La réponse la plus simple à cette question est posée: "Parfois, lorsque la réponse est lente, on peut cliquer plusieurs fois sur le bouton d'envoi. Comment éviter que cela ne se produise?"

Désactivez simplement le bouton d'envoi de formulaire, comme le code ci-dessous.

<form ... onsubmit="buttonName.disabled=true; return true;">
  <input type="submit" name="buttonName" value="Submit">
</form>

Cela désactivera le bouton de soumission, au premier clic pour la soumission. De plus, si vous avez des règles de validation, cela fonctionnera très bien. J'espère que cela aidera.

Imran Khan
la source
Je pense qu'il vous manque quelque chose, veuillez poster votre code.
Imran Khan
3

Du côté client , vous devez désactiver le bouton d'envoi une fois que le formulaire est soumis avec du code javascript comme la méthode fournie par @vanstee et @chaos.

Mais il y a un problème de retard du réseau ou de situation de désactivation de javascript où vous ne devriez pas compter sur le JS pour empêcher que cela se produise.

Donc, côté serveur , vous devriez vérifier la soumission répétée des mêmes clients et omettre la soumission répétée qui semble une fausse tentative de l'utilisateur.

steveyang
la source
Je sais que cela a été répondu il y a longtemps, mais quelqu'un peut-il expliquer comment le décalage du réseau pourrait empêcher la désactivation? Je suis confronté à ce problème en ce moment et je suis très confus quant à la façon dont un formulaire a été soumis en double même si je désactive le bouton. Je n'ai même jamais pensé à JavaScript désactivé. Je ne pense pas que ce soit le problème dans mon cas, mais c'est néanmoins un aperçu intéressant.
davidatthepark
J'envisageais également d'étrangler le gestionnaire de clics.
davidatthepark
3

Vous pouvez essayer le plugin safeform jquery.

$('#example').safeform({
    timeout: 5000, // disable form on 5 sec. after submit
    submit: function(event) {
        // put here validation and ajax stuff...

        // no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
})
Max Kamenkov
la source
1

La solution la plus simple et élégante pour moi:

function checkForm(form) // Submit button clicked
{
    form.myButton.disabled = true;
    form.myButton.value = "Please wait...";
    return true;
}

<form method="POST" action="..." onsubmit="return checkForm(this);">
    ...
    <input type="submit" name="myButton" value="Submit">
</form>

Lien pour en savoir plus ...

Solis
la source
1

Utilisez ce code dans votre formulaire. Il gérera plusieurs clics.

<script type="text/javascript">
    $(document).ready(function() {
        $("form").submit(function() {
            $(this).submit(function() {
                return false;
            });
            return true;
        });     
    }); 
</script>

cela fonctionnera à coup sûr.

Bachas
la source
1

Cela permet de soumettre toutes les 2 secondes. En cas de validation frontale.

$(document).ready(function() {
    $('form[debounce]').submit(function(e) {
        const submiting = !!$(this).data('submiting');

        if(!submiting) {
            $(this).data('submiting', true);

            setTimeout(() => {
                $(this).data('submiting', false);
            }, 2000);

            return true;
        }

        e.preventDefault();
        return false;
    });
})
Aurel
la source
0

la meilleure façon d'empêcher la soumission multiple est de transmettre simplement l'identifiant du bouton dans la méthode.

    function DisableButton() {
        document.getElementById("btnPostJob").disabled = true;
    }
    window.onbeforeunload = DisableButton; 
user2427182
la source
0

Pour ce faire, utiliser javascript est un peu facile. Voici le code qui donnera la fonctionnalité souhaitée:

$('#disable').on('click', function(){
    $('#disable').attr("disabled", true);
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="disable">Disable Me!</button>

Rish
la source
0

Les solutions les plus simples sont de désactiver le bouton au clic, de l'activer une fois l'opération terminée. Pour vérifier une solution similaire sur jsfiddle:

[click here][1]

Et vous pouvez trouver une autre solution sur cette réponse .

Kalyani
la source
1
Bien qu'un lien soit génial, veuillez fournir un contexte à vos liens , car une réponse doit en fait contenir une réponse. Sachez qu'être à peine plus qu'un lien vers un site externe est une raison possible pour savoir pourquoi et comment certaines réponses sont supprimées? .
janvier
0

Cela fonctionne très bien pour moi. Il soumet la ferme et rend le bouton désactivé et après 2 secondes, active le bouton.

<button id="submit" type="submit" onclick="submitLimit()">Yes</button>

function submitLimit() {
var btn = document.getElementById('submit')
setTimeout(function() {
    btn.setAttribute('disabled', 'disabled');
}, 1);

setTimeout(function() {
    btn.removeAttribute('disabled');
}, 2000);}

Dans le Syntex ECMA6

function submitLimit() {
submitBtn = document.getElementById('submit');

setTimeout(() => { submitBtn.setAttribute('disabled', 'disabled') }, 1);

setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}
Awais Jameel
la source
0

Juste pour ajouter aux réponses possibles sans contourner la validation d'entrée du navigateur

$( document ).ready(function() {
    $('.btn-submit').on('click', function() {
        if(this.form.checkValidity()) {
            $(this).attr("disabled", "disabled");
            $(this).val("Submitting...");
            this.form.submit();
        }
    });
});
Roi
la source
0

Une alternative à ce qui a été proposé auparavant est:

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
Kisded Szabi - CodeRevolution
la source