jQuery: come ottenere quale pulsante è stato fatto clic sull'invio del modulo?


227

Ho organizzato un .submit()evento per l'invio del modulo. Ho anche più moduli sulla pagina, ma solo uno qui per questo esempio. Mi piacerebbe sapere quale pulsante di invio è stato cliccato senza applicare un .click()evento a ciascuno.

Ecco la configurazione:

<html>
<head>
  <title>jQuery research: forms</title>
  <script type='text/javascript' src='../jquery-1.5.2.min.js'></script>
  <script type='text/javascript' language='javascript'>
      $(document).ready(function(){
          $('form[name="testform"]').submit( function(event){ process_form_submission(event); } );
      });
      function process_form_submission( event ) {
          event.preventDefault();
          //var target = $(event.target);
          var me = event.currentTarget;
          var data = me.data.value;
          var which_button = '?';       // <-- this is what I want to know
          alert( 'data: ' + data + ', button: ' + which_button );
      }
  </script>
</head>
<body>
<h2>Here's my form:</h2>
<form action='nothing' method='post' name='testform'>
  <input type='hidden' name='data' value='blahdatayadda' />
  <input type='submit' name='name1' value='value1' />
  <input type='submit' name='name2' value='value2' />
</form>
</body>
</html>

Esempio dal vivo su jsfiddle

Oltre ad applicare un evento .click () su ciascun pulsante, c'è un modo per determinare quale pulsante di invio è stato cliccato?


2
L'ironia è ovviamente che queste informazioni sono insignificanti nel determinare il lato server.
Neil,

5
@Neil Non se stai inviando il modulo tramite $ .ajax () e un serializeArray () sul modulo.
Aaron,


1
Che ne dici di mettere un ascoltatore sui pulsanti di invio e inviare il modulo manualmente.
JMRC,

1
Che ne dite di guardare la versione serializzata dei dati del modulo e abbinare sui pulsanti name?
Augustin Riedinger,

Risposte:


235

Ho posto la stessa domanda: come posso ottenere il pulsante che ha causato l'invio dall'evento di invio del modulo?

Ho finito per trovare questa soluzione e ha funzionato abbastanza bene:

$(document).ready(function() {
    $("form").submit(function() { 
        var val = $("input[type=submit][clicked=true]").val();
        // DO WORK
    });
    $("form input[type=submit]").click(function() {
        $("input[type=submit]", $(this).parents("form")).removeAttr("clicked");
        $(this).attr("clicked", "true");
    });
});

Nel tuo caso con più moduli potrebbe essere necessario modificarlo un po ', ma dovrebbe comunque essere applicato


11
+1 Bella soluzione. È possibile che si desideri aggiungere un'istruzione che reimposta l'attributo selezionato su false tra i pulsanti nel caso in cui il modulo di invio venga gestito in modo ajax e si desideri evitare di ottenere nuovamente il pulsante precedentemente fatto clic.
Chandu,

1
Oh, capisco. Stai aggiungendo il tuo attributo "cliccato". Stavo cercando un booleano "cliccato" e non riuscivo a trovarlo da nessuna parte. Non ho mai pensato di crearne uno io. Buona idea!
Hawkexp,

9
Ricorda che funziona solo con elementi di input, non con elementi di pulsanti.
Bob.at.Indigo.Health,

1
Questo non è necessario in Chrome con elementi di pulsante. Gestisco semplicemente l'evento di invio, costruisco un oggetto FormData dal modulo e include sempre il valore del pulsante su cui è stato fatto clic. FireFox NON presenta questo comportamento e invece non invia affatto il valore del pulsante. Chrome sembra fare automaticamente qualcosa come la soluzione sopra, ricordando quale pulsante è stato fatto clic e includendolo automaticamente nei dati del modulo. Naturalmente, questa mancanza di comportamento standard (affliggendo comunque tutto in JavaScript, quindi non mi sorprende), rende la funzione inutile.
Triynko,

1
Inoltre, considera di aggiungere il selettore "button [type = submit]" (separato da virgola) poiché gli elementi submit non devono essere tag di input.
Kyselejsyreček,

91

Ho scoperto che ha funzionato.

$(document).ready(function() {
    $( "form" ).submit(function () {
        // Get the submit button element
        var btn = $(this).find("input[type=submit]:focus" );
    });
}

12
questa soluzione funziona bene su Chrome, ma non può funzionare su Safari, tornerà indefinito, non l'oggetto pulsante
Mr. Sun Lin

1
@Krinkle L'ho codificato in questo modo per mostrare il modo più generico possibile. Penso che gli sviluppatori siano abbastanza intelligenti da ottimizzarli secondo i loro gusti.
Stan,

Più pulito rispetto alle altre soluzioni. Non ho ancora trovato una soluzione che
funzioni

Questa risposta non funzionerà sempre. In realtà è necessario il pulsante cliccato, non il focus (poiché l'azione focus non è un'azione click). La risposta selezionata (del cacciatore) è quella corretta.
Vasil Popov,

Ho un evento click sui pulsanti di invio e invio eventi nei loro moduli ... quest'ultimo attiva il primo. Ho usato questo per capire l'origine dell'evento. In alcuni browser facendo clic sul pulsante otterrai il pulsante come focalizzato, in altri non otterrai nulla. In tutti i browser che ho testato, premendo invio mentre su un input mantiene l'input focalizzato.
notacouch

65

Questo funziona per me:

$("form").submit(function() {
   // Print the value of the button that was clicked
   console.log($(document.activeElement).val());
}

3
Questo è stato utile, per ottenere il iddel activeElement, l'ho fatto$(document.activeElement).attr('id');
Mikolaj

9
Per quello che vale, non è necessario utilizzare jQuery per ottenere l'id - è ancora più semplice usare Javascript puro:document.activeElement.id
Nick F

5
Si noti che questo non sembra funzionare come previsto su Safari. :(
rinogo,

@rinogo: cosa succede in Safari?
Crescent Fresh,

1
In Safari document.activeElementnon è l'input. Nel mio caso è un div modale (che contiene il modulo).
mgalgs

46

Quando viene inviato il modulo:

  • document.activeElement ti darà il pulsante di invio che è stato cliccato.

  • document.activeElement.getAttribute('value') ti darà il valore di quel pulsante.


2
Si noti che questo non sembra funzionare come previsto su Safari. :(
rinogo,

Non so come su Safari, ma su Chrome ha funzionato bene :) Grazie!
Ingus,

Funziona in Chrome 63 e IE11
Sir Crispalot,

Ho avuto la convalida discreta jquery in esecuzione, e questo intercetta prima di questo e imposta l'input non valido come activeElement invece del pulsante.
Peheje,

28

Ecco l'approccio che sembra più pulito per i miei scopi.

Innanzitutto, per tutte le forme:

$('form').click(function(event) {
  $(this).data('clicked',$(event.target))
});

Quando questo evento clic viene generato per un modulo, registra semplicemente la destinazione di origine (disponibile nell'oggetto evento) a cui è possibile accedere in un secondo momento. Questo è un tratto piuttosto ampio, poiché si attiva per qualsiasi clic in qualsiasi punto del modulo. I commenti di ottimizzazione sono ben accetti, ma sospetto che non causeranno mai problemi evidenti.

Quindi, in $('form').submit(), puoi chiedere quale è stato l'ultimo clic, con qualcosa del genere

if ($(this).data('clicked').is('[name=no_ajax]')) xhr.abort();

Cosa succede se si tratta di un evento di invio di un modulo anziché di un clic?
Tony,

1
@Tony, scusa se non ho visto prima la tua domanda. Questa risposta riguarda interamente i moduli inviati. Anche i pulsanti di invio vengono cliccati e quindi generano l'evento click.
Jonathan Camenisch,

2
L'upgrade di questa risposta alla risposta del cacciatore in quanto gli eventi di invio del modulo vengono attivati ​​prima di qualsiasi evento di clic dell'elemento figlio. Ciò causa difficoltà quando l'evento di invio del modulo viene annullato con return false, mentre questo metodo funziona correttamente poiché il clic è associato al modulo anziché ai suoi figli.
pospi,

7
Questo non riesce a gestire correttamente il caso in cui il modulo viene inviato con mezzi diversi da un clic (ad esempio, premendo Invio). Quando il modulo viene inviato con altri mezzi, è il primo pulsante di invio che ha attivato l'evento di invio, non l'ultimo clic.
quietmint

Manca un punto e virgola dopo, ... $(event.target))ma non può essere modificato perché le modifiche devono essere> 6 caratteri
Hafenkranich,

13

Caspita, alcune soluzioni possono complicarsi! Se non ti dispiace usare un semplice globale, approfitta semplicemente del fatto che l'evento di clic del pulsante di input viene attivato per primo. Si potrebbe ulteriormente filtrare il selettore $ ('input') per uno dei molti moduli usando $ ('# input myForm').

    $(document).ready(function(){
      var clkBtn = "";
      $('input[type="submit"]').click(function(evt) {
        clkBtn = evt.target.id;
      });

      $("#myForm").submit(function(evt) {
        var btnID = clkBtn;
        alert("form submitted; button id=" + btnID);
      });
    });

12

Ho trovato la soluzione migliore

$(document.activeElement).attr('id')

Questo non funziona solo sugli input, ma funziona anche sui tag dei pulsanti. Inoltre ottiene l'ID del pulsante.


Accidenti devo vedere se la mia pagina funziona su Safari ora doh. Perché Safari deve essere sempre così difficile. Grazie per quello Vado a controllare quando torno a casa
Thomas Williams,


Questo non funziona per me in Safari. Fare clic su listener su un pulsante nel corpo chiama .submit su un modulo. All'interno del gestore invio $(document.activeElement).attr('id')restituisceundefined
dyodji il

7

Un'altra possibile soluzione è aggiungere un campo nascosto nel modulo:

<input type="hidden" id="btaction"/>

Quindi nella funzione pronto aggiungi le funzioni per registrare quale tasto è stato premuto:

$('form#myForm #btnSubmit').click(function() {
    $('form#myForm #btaction').val(0);
});

$('form#myForm #btnSubmitAndSend').click(function() {
    $('form#myForm #btaction').val(1);
});

$('form#myForm #btnDelete').click(function() {
    $('form#myForm #btaction').val(2);
});

Ora nel gestore della presentazione del modulo leggi la variabile nascosta e decidi in base ad essa:

var act = $('form#myForm #btaction').val();

6

Basandosi su ciò che Stan e yann-h hanno fatto, ma questo di default è il primo pulsante. La bellezza di questo approccio generale è che raccoglie sia il clic che il tasto Invio (anche se lo stato attivo non era sul pulsante. Se è necessario consentire l'accesso nel modulo, quindi rispondere a questo solo quando un pulsante è attivo ( cioè la risposta di Stan.) Nel mio caso, volevo consentire a enter di inviare il modulo anche se il focus attuale dell'utente era sulla casella di testo.

Stavo anche usando un attributo 'name' piuttosto che 'id' ma questo è lo stesso approccio.

var pressedButtonName =
     typeof $(":input[type=submit]:focus")[0] === "undefined" ?
     $(":input[type=submit]:first")[0].name :
     $(":input[type=submit]:focus")[0].name;

Quindi, se si sposta lo stato attivo sul secondo pulsante con TAB e si preme INVIO, verrà impostato automaticamente il primo pulsante ...
FrancescoMM,

5

Questo ha funzionato per me

$('#Form').submit(function(){
var btn= $(this).find("input[type=submit]:focus").val();
alert('you have clicked '+ btn);

}

Questo merita una medaglia!
Martin Zvarík,

4

Se ciò che vuoi dire non aggiungendo un evento .click è che non vuoi avere gestori separati per quegli eventi, puoi gestire tutti i clic (invii) in una funzione:

$(document).ready(function(){
  $('input[type="submit"]').click( function(event){ process_form_submission(event); } );
});

function process_form_submission( event ) {
  event.preventDefault();
  //var target = $(event.target);
  var input = $(event.currentTarget);
  var which_button = event.currentTarget.value;
  var data = input.parents("form")[0].data.value;
//  var which_button = '?';       // <-- this is what I want to know
  alert( 'data: ' + data + ', button: ' + which_button );
}

non è una cattiva idea. Funzionerebbe per qualsiasi numero di moduli nella pagina?
Hawkexp,

@hawk sì, dovrebbe. Non so se questo è il comportamento desiderato, ma il tuo codice in realtà non invia il modulo, quindi neanche il mio. Se vuoi inviarlo basta rimuovere event.preventDefaulto fare qualcosa di simile input.parents("form")[0].submit().
jcane86,

E se invii senza un clic (tasto di ritorno?) Sarà un disastro totale ..
FrancescoMM

4

Poiché non posso commentare la risposta accettata, porto qui una versione modificata che dovrebbe tenere conto degli elementi esterni al modulo (ovvero: allegati al modulo utilizzando l' formattributo). Questo è per il browser moderno: http://caniuse.com/#feat=form-attribute . La closest('form') viene usato come ripiego per non supportato formattributo

$(document).on('click', '[type=submit]', function() {
    var form = $(this).prop('form') || $(this).closest('form')[0];
    $(form.elements).filter('[type=submit]').removeAttr('clicked')
    $(this).attr('clicked', true);
});

$('form').on('submit', function() {
    var submitter = $(this.elements).filter('[clicked]');
})

Questa dovrebbe davvero essere la risposta selezionata. Vorrei solo aggiungere che la regola dovrebbe essere"button,[type=submit]"
Wil

@Wil ma non tutti i pulsanti sono pulsanti di invio, dipende dal loro tipo.
ptyskju,

Sì, ma in assenza di <input type = "submit">], ogni UA che abbia mai usato ha trattato un tag <button> come il trigger di invio del modulo, quindi questo accadrà in quel caso. Oppure l'autore può aggiungere un avvertimento sul fatto che tutti gli elementi in grado di presentare devono avere proprietà [type = submit] ... uno degli altri.
Wil

3
$("form input[type=submit]").click(function() {
    $("<input />")
        .attr('type', 'hidden')
        .attr('name', $(this).attr('name'))
        .attr('value', $(this).attr('value'))
    .appendTo(this)
});

aggiungi campo nascosto


Non funziona in Firefox 30 / Windows 7. Nota: ora è necessario un campo nascosto in Firefox, poiché potrebbe non inviare il valore di invio selezionato se inviato con jquery: this.submit () in un evento di invio. Sono solo un po 'preoccupato che $ (questo) .attr (' nome ') potrebbe non funzionare su tutti i browser.
user1610743,

Ho Firefox 30 / Windows 7. Ho tutto perfettamente funzionante.
Anydasa,

Ricorda di includere button[type=submit]e input[type=image].
Rybo111,

3

Per me, la soluzione migliore è stata questa:

$(form).submit(function(e){

   // Get the button that was clicked       
   var submit = $(this.id).context.activeElement;

   // You can get its name like this
   alert(submit.name)

   // You can get its attributes like this too
   alert($(submit).attr('class'))

});

3

Lavorando con questa eccellente risposta , puoi controllare l'elemento attivo (il pulsante), aggiungere un input nascosto al modulo e, facoltativamente, rimuoverlo alla fine del gestore di invio.

$('form.form-js').submit(function(event){
    var frm = $(this);
    var btn = $(document.activeElement);
    if(
        btn.length &&
        frm.has(btn) &&
        btn.is('button[type="submit"], input[type="submit"], input[type="image"]') &&
        btn.is('[name]')
    ){
        frm.append('<input type="hidden" id="form-js-temp" name="' + btn.attr('name') + '" value="' + btn.val() + '">');
    }

    // Handle the form submit here

    $('#form-js-temp').remove();
});

Nota a margine: aggiungo personalmente la classe form-jsa tutti i moduli inviati tramite JavaScript.


2

Simile alla risposta di Stan ma:

  • se hai più di un pulsante, devi ottenere solo il primo pulsante => [0]
  • se il modulo può essere inviato con il tasto Invio, devi gestire un default => myDefaultButtonId

$(document).on('submit', function(event) {
    event.preventDefault();
    var pressedButtonId = 
         typeof $(":input[type=submit]:focus")[0] === "undefined" ? 
         "myDefaultButtonId" :
         $(":input[type=submit]:focus")[0].id;
    ...
 }

2

Questa è la soluzione usata da me e funziona molto bene:

// prevent enter key on some elements to prevent to submit the form
function stopRKey(evt) {
  evt = (evt) ? evt : ((event) ? event : null);
  var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
  var alloved_enter_on_type = ['textarea'];
  if ((evt.keyCode == 13) && ((node.id == "") || ($.inArray(node.type, alloved_enter_on_type) < 0))) {
    return false;
  }
}

$(document).ready(function() {
  document.onkeypress = stopRKey;
  // catch the id of submit button and store-it to the form
  $("form").each(function() {
    var that = $(this);

    // define context and reference
    /* for each of the submit-inputs - in each of the forms on
			 the page - assign click and keypress event */
    $("input:submit,button", that).bind("click keypress", function(e) {
      // store the id of the submit-input on it's enclosing form
      that.data("callerid", this.id);
    });
  });

  $("#form1").submit(function(e) {
    var origin_id = $(e.target).data("callerid");
    alert(origin_id);
    e.preventDefault();

  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form id="form1" name="form1" action="" method="post">
  <input type="text" name="text1" />
  <input type="submit" id="button1" value="Submit1" name="button1" />
  <button type="submit" id="button2" name="button2">
    Submit2
  </button>
  <input type="submit" id="button3" value="Submit3" name="button3" />
</form>



1

Ecco la mia soluzione:

   $('#form').submit(function(e){   
        console.log($('#'+e.originalEvent.submitter.id));
        e.preventDefault();
    });

0

Ho anche creato una soluzione e funziona abbastanza bene:
utilizza jQuery e CSS


Innanzitutto, ho creato una rapida classe CSS, che può essere incorporata o in un file separato.

<style type='text/css'>
    .Clicked {
        /*No Attributes*/
    }
</style>


Successivamente, nell'evento clic di un pulsante all'interno del modulo, aggiungi la classe CSS al pulsante. Se il pulsante ha già la classe CSS, rimuoverlo. (Non vogliamo due classi CSS [solo nel caso]).

    // Adds a CSS Class to the Button That Has Been Clicked.
    $("form :input[type='submit']").click(function () 
    {
        if ($(this).hasClass("Clicked"))
        {
            $(this).removeClass("Clicked");
        }
        $(this).addClass("Clicked");
    });


Ora, prova il pulsante per vedere che ha la classe CSS, se il pulsante testato non ha il CSS, allora l'altro pulsante lo farà.

    // On Form Submit
    $("form").submit(function ()
    {
        // Test Which Button Has the Class
        if ($("input[name='name1']").hasClass("Clicked"))
        {
            // Button 'name1' has been clicked.
        }
        else
        {
           // Button 'name2' has been clicked.
        }
    });

Spero che questo ti aiuti! Saluti!


Ricorda di includere button[type=submit]e input[type=image].
Rybo111,

È necessario rimuovere i riferimenti allo stile e ai CSS: non sono rilevanti qui. Inoltre, le linee in cui usi hasClass()e removeClass()sono ridondanti, poiché addClass()non aggiungeranno la stessa classe due volte.
Rybo111,

0

È possibile creare input type = "hidden" come supporto per le informazioni sull'ID pulsante.

<input type="hidden" name="button" id="button">
<input type="submit" onClick="document.form_name.button.value = 1;" value="Do something" name="do_something">

In questo caso il modulo passa il valore "1" (ID del tuo pulsante) al momento dell'invio. Funziona se onClick si verifica prima di inviare (?), Cosa non sono sicuro che sia sempre vero.


0

Un modo semplice per distinguere quale <button> o <input type = "button" ...> viene premuto, controllando il loro 'id':

$("button").click(function() {
  var id = $(this).attr('id');
  ... 
});

0

Ecco un esempio, che utilizza this.form per ottenere la forma corretta in cui si trova l'invio, e campi dati per memorizzare l'ultimo elemento cliccato / focalizzato. Ho anche inserito il codice di invio all'interno di un timeout per essere sicuro che gli eventi di clic si verifichino prima che vengano eseguiti (alcuni utenti hanno segnalato nei commenti che su Chrome a volte viene generato un evento di clic dopo un invio).

Funziona quando si naviga sia con i tasti che con il mouse / le dita senza contare sui browser per inviare un evento clic sul tasto INVIO (non fa male però), ho aggiunto un gestore eventi per eventi di messa a fuoco per pulsanti e campi.

È possibile aggiungere pulsanti di tipo = "invia" agli elementi che si salvano quando si fa clic.

Nella demo ho impostato un bordo rosso per mostrare l'elemento selezionato e un avviso che mostra nome e valore / etichetta.

Ecco il FIDDLE

Ed ecco il (stesso) codice:

Javascript:

$("form").submit(function(e) {
  e.preventDefault();
  // Use this for rare/buggy cases when click event is sent after submit
  setTimeout(function() {

    var $this=$(this);
    var lastFocus = $this.data("lastFocus");
    var $defaultSubmit=null;

    if(lastFocus) $defaultSubmit=$(lastFocus);

    if(!$defaultSubmit || !$defaultSubmit.is("input[type=submit]")) {
      // If for some reason we don't have a submit, find one (the first)
      $defaultSubmit=$(this).find("input[type=submit]").first();
    }

    if($defaultSubmit) {
      var submitName=$defaultSubmit.attr("name");
      var submitLabel=$defaultSubmit.val();

       // Just a demo, set hilite and alert
      doSomethingWith($defaultSubmit);
      setTimeout(function() {alert("Submitted "+submitName+": '"+submitLabel+"'")},1000);
    } else {
      // There were no submit in the form
    }

  }.bind(this),0);

});

$("form input").focus(function() {
  $(this.form).data("lastFocus", this);
});
$("form input").click(function() {
  $(this.form).data("lastFocus", this);
});

// Just a demo, setting hilite
function doSomethingWith($aSelectedEl) {
  $aSelectedEl.css({"border":"4px solid red"});
  setTimeout(function() { $aSelectedEl.removeAttr("style"); },1000);
}

HTML DUMMY:

<form>
<input type="text" name="testtextortexttest" value="Whatever you write, sir."/>
<input type="text" name="moretesttextormoretexttest" value="Whatever you write, again, sir."/>

<input type="submit" name="test1" value="Action 1"/>
<input type="submit" name="test2" value="Action 2"/>
<input type="submit" name="test3" value="Action 3"/>
<input type="submit" name="test4" value="Action 4"/>
<input type="submit" name="test5" value="Action 5"/>
</form>

CSS DUMB:

input {display:block}

0

Scrivo questa funzione che mi aiuta

var PupulateFormData= function (elem) {
var arr = {};
$(elem).find("input[name],select[name],button[name]:focus,input[type='submit']:focus").each(function () {
    arr[$(this).attr("name")] = $(this).val();
});
return arr;
};

e quindi Usa

var data= PupulateFormData($("form"));

0
$('form').submit(function (ev) {
  let clickedButton = ev.originalEvent.explicitOriginalTarget;
});

-1

Vuoi usare window.event.srcElement.id in questo modo:

function clickTheButton() {

var Sender = window.event.srcElement;
alert("the item clicked was " + Sender.id)

}

per un pulsante simile a:

<input type="button" id="myButton" onclick="clickTheButton();" value="Click Me"/>

riceverai un avviso che dice: "l'elemento selezionato era myButton.

Nel tuo esempio migliorato puoi aggiungere window.event.srcElement a process_form_submission e avrai un riferimento a qualunque elemento invocato il processo.


1
non usare onclick per gli elementi, è deprecato
Krzysztof Cygan

1
Questo non sembra funzionare per i pulsanti di invio, window.event.srcElement restituisce l'ID del modulo.
333 MHz

@KrzysztofCygan Ne hai qualche fonte?
vard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.