Prevenire il doppio invio di moduli in jQuery

Ho un modulo che richiede un po ‘di tempo per il server da elaborare. Devo garantire che l’utente sia in attesa e non tenti di inviare nuovamente il modulo facendo nuovamente clic sul pulsante. Ho provato a utilizzare il seguente codice jQuery:

 $(document).ready(function() { $("form#my_form").submit(function() { $('input').attr('disabled', 'disabled'); $('a').attr('disabled', 'disabled'); return true; }); });  

Quando provo questo in Firefox tutto viene disabilitato ma il modulo non viene inviato con nessuno dei dati POST che dovrebbe includere. Non posso usare jQuery per inviare il modulo perché ho bisogno del pulsante per essere inviato con il modulo in quanto vi sono più pulsanti di invio e determino quale è stato utilizzato da quale valore è incluso nel POST. Ho bisogno che il modulo sia presentato come al solito e ho bisogno di disabilitare tutto subito dopo.

Grazie!

Penso che il tuo problema sia questa linea:

 $('input').attr('disabled','disabled'); 

Stai disabilitando TUTTI gli input, compresi, suppongo, quelli i cui dati devono essere inviati dal modulo.

Per disabilitare solo i pulsanti di invio, puoi fare ciò:

 $('button[type=submit], input[type=submit]').prop('disabled',true); 

Tuttavia, non penso che IE invierà il modulo se anche quei pulsanti sono disabilitati. Suggerirei un approccio diverso.

Un plugin jQuery per risolverlo

Abbiamo appena risolto questo problema con il seguente codice. Il trucco qui sta usando i data() di jQuery data() per contrassegnare il modulo come già inviato o meno. In questo modo, non dobbiamo scherzare con i pulsanti di invio, il che fa impazzire 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; }; 

Usalo in questo modo:

 $('form').preventDoubleSubmission(); 

Se ci sono moduli AJAX che dovrebbero essere autorizzati a inviare più volte per caricamento della pagina, puoi dare loro una class che li indichi, quindi escluderli dal tuo selettore in questo modo:

 $('form:not(.js-allow-double-submission)').preventDoubleSubmission(); 

L’approccio al tempismo è sbagliato – come fai a sapere quanto tempo impiegherà l’azione sul browser del cliente?

Come farlo

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

Quando il modulo viene inviato, disabiliterà tutti i pulsanti di invio all’interno.

Ricorda che in Firefox quando disabiliti un pulsante questo stato verrà ricordato quando tornerai indietro nella storia. Per evitare di dover abilitare i pulsanti al caricamento della pagina, ad esempio.

Penso che la risposta di Nathan Long sia la strada da percorrere. Per me, sto usando la validazione lato client, quindi ho appena aggiunto una condizione per cui il modulo è valido.

EDIT : se questo non viene aggiunto, l’utente non sarà mai in grado di inviare il modulo se la convalida sul lato client riscontra un errore.

  // 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 non funziona in Firefox. Restituire false non è standard, dovresti chiamare event.preventDefault() . E mentre ci siamo, usiamo sempre le parentesi graffe con un costrutto di controllo .

Per riassumere tutte le risposte precedenti, ecco un plugin che fa il lavoro e funziona 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; }); }; 

Per affrontare Kern3l, il metodo di temporizzazione funziona per me semplicemente perché stiamo cercando di fermare un doppio clic del pulsante di invio. Se hai un tempo di risposta molto lungo per una submission, ti consiglio di sostituire il pulsante di invio o il modulo con uno spinner.

Il blocco totale delle presentazioni successive del modulo, come fa la maggior parte degli esempi precedenti, ha un effetto collaterale negativo: se si verifica un errore di rete e si desidera provare a inviare nuovamente, non sarebbero in grado di farlo e perderebbero le modifiche. fatto. Questo sicuramente farebbe un utente arrabbiato.

Per favore, controlla il plugin jquery-safeform .

Esempio di utilizzo:

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

… ma il modulo non viene inviato con nessuno dei dati POST che si suppone includa.

Corretta. I nomi / i valori degli elementi del modulo disabilitati non verranno inviati al server. Dovresti impostarli come elementi di sola lettura .

Inoltre, le ancore non possono essere disabilitate in questo modo. Dovrai rimuovere i loro HREF (non consigliato) o impedire il loro comportamento predefinito (modo migliore), ad esempio:

  

C’è la possibilità di migliorare l’ approccio di Nathan Long. È ansible sostituire la logica per il rilevamento del modulo già inviato con questo:

 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 

Il codice di Nathan ma per il plugin jQuery Validate

Se ti capita di utilizzare il plugin jQuery Validate, hanno già implementato il gestore di invio, e in tal caso non c’è motivo di implementarne più di uno. Il codice:

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

Puoi facilmente espanderlo nel } else { -block per disabilitare input e / o pulsante di invio.

Saluti

Ho finito per usare le idee di questo post per trovare una soluzione che fosse abbastanza simile alla versione di 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; }); }; 

Usando così:

 $('#my-form').preventDoubleSubmission(); 

Ho scoperto che le soluzioni che non includevano qualche tipo di timeout ma solo l'invio disabilitato o gli elementi del modulo disabilitati hanno causato problemi perché una volta triggersto il blocco non è ansible inviare nuovamente fino a quando non si aggiorna la pagina. Ciò mi causa alcuni problemi quando faccio cose ajax.

Questo può probabilmente essere un po 'più bello, non è così elegante.

Se si utilizza AJAX per pubblicare un modulo, impostare async: false dovrebbe impedire ulteriori sottomissioni prima che il modulo venga cancellato:

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

Modificata la soluzione di Nathan un po ‘per Bootstrap 3. Questo imposterà un testo di caricamento sul pulsante di invio. Inoltre, si spegnerà dopo 30 secondi e consentirà di inviare nuovamente il modulo.

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

Utilizza due pulsanti di invio.

   

E jQuery:

 $("#sub").click(function(){ $(this).val("Please wait.."); $(this).attr("disabled","disabled"); $("#sub2").click(); }); 

Ho riscontrato problemi simili e le mie soluzioni sono le seguenti.

Se non hai alcuna convalida sul lato client, puoi semplicemente utilizzare il metodo jquery one () come documentato qui.

http://api.jquery.com/one/

Questo disabilita il gestore dopo che è stato richiamato.

 $("#mysavebuttonid").on("click", function () { $('form').submit(); }); 

Se stai facendo la validazione lato client come stavo facendo, è leggermente più complicato. L’esempio precedente non ti consente di inviare nuovamente dopo la convalida non riuscita. Prova invece questo approccio

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

ecco come lo faccio:

 $(document).ready(function () { $('.class_name').click(function () { $(this).parent().append(''); $(this).hide(); }); }); 

crediti: https://github.com/phpawy/jquery-submit-once

questo codice mostrerà il caricamento sull’etichetta del pulsante e il pulsante su

disabilita lo stato, quindi dopo l’elaborazione, ritriggers e ritorna indietro il testo del pulsante originale **

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

);

La mia soluzione:

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

Nel mio caso, il modulo di invio ha avuto un codice di convalida, quindi incremento la risposta di Nathan Long includendo un checkpoint 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; }; 

Cambia pulsante di invio:

  

Con il pulsante normale:

  

Quindi utilizzare la funzione clic:

 $("#submitButtonId").click(function () { $('#submitButtonId').prop('disabled', true); $('#myForm').submit(); }); 

E ricorda il pulsante di ritriggerszione quando è necessario:

 $('#submitButtonId').prop('disabled', false); 

Utilizza il contatore semplice su submit.

  var submitCounter = 0; function monitor() { submitCounter++; if (submitCounter < 2) { console.log('Submitted. Attempt: ' + submitCounter); return true; } console.log('Not Submitted. Attempt: ' + submitCounter); return false; } 

E la funzione call monitor() invia il modulo.

  
....

Ho risolto un problema molto simile usando:

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