Come viene determinato il pulsante di invio predefinito su un modulo HTML?


210

Se viene inviato un modulo ma non tramite alcun pulsante specifico, ad esempio

  • premendo Enter
  • usando HTMLFormElement.submit()in JS

come si suppone che un browser determini quale di più pulsanti di invio utilizzare, se presente, come quello premuto?

Questo è significativo su due livelli:

  • chiamando un onclickgestore eventi collegato a un pulsante di invio
  • i dati inviati al server web

I miei esperimenti finora hanno dimostrato che:

  • quando si preme Enter, Firefox, Opera e Safari utilizzano il primo pulsante di invio nel modulo
  • quando si preme Enter, IE utilizza il primo pulsante di invio o nessuno a seconda delle condizioni che non sono stato in grado di capire
  • tutti questi browser non ne usano affatto per un invio a JS

Cosa dice lo standard?

Se potrebbe aiutare, ecco il mio codice di test (il PHP è rilevante solo per il mio metodo di test, non per la mia stessa domanda)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>

<body>

<h1>Get</h1>
<dl>
<?php foreach ($_GET as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<h1>Post</h1>
<dl>
<?php foreach ($_POST as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<form name="theForm" method="<?php echo isset($_GET['method']) ? $_GET['method'] : 'get'; ?>" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>">
    <input type="text" name="method" />
    <input type="submit" name="action" value="Button 1" onclick="alert('Button 1'); return true" />
    <input type="text" name="stuff" />
    <input type="submit" name="action" value="Button 2" onclick="alert('Button 2'); return true" />
    <input type="button" value="submit" onclick="document.theForm.submit();" />
</form>

</body></html>

Risposte:


115

Se invii il modulo tramite Javascript (ovvero formElement.submit()qualsiasi cosa equivalente), nessuno dei pulsanti di invio viene considerato corretto e nessuno dei loro valori viene incluso nei dati inviati. (Tieni presente che se invii il modulo utilizzando, submitElement.click()allora l'invio a cui avevi un riferimento è considerato attivo; questo non rientra davvero nel mandato della tua domanda poiché qui il pulsante di invio non è ambiguo ma ho pensato di includerlo per le persone che leggono la prima parte e si chiedono come fare in modo che un pulsante di invio abbia successo tramite l'invio del modulo JS. Naturalmente, i gestori onsubmit del modulo continueranno a sparare in questo modo mentre non lo farebbero tramite form.submit()questo è un altro bollitore di pesce ...)

Se il modulo viene inviato premendo Invio mentre si trova in un campo non textarea, spetta all'agente dell'utente decidere cosa desidera qui. Le specifiche non dicono nulla sull'invio di un modulo usando il tasto Invio mentre ci si trova in un campo di immissione testo (se si fa clic su un pulsante e lo si attiva utilizzando lo spazio o altro, non c'è alcun problema in quanto quel pulsante di invio specifico viene utilizzato in modo inequivocabile). Tutto ciò che dice è che un modulo deve essere inviato quando viene attivato un pulsante di invio, non è nemmeno un requisito che premendo invio in un input di testo invierà il modulo.

Credo che Internet Explorer scelga il pulsante di invio che appare per primo nella fonte; Ho la sensazione che Firefox e Opera scelgano il pulsante con il tabindex più basso, tornando al primo definito se non viene definito nient'altro. Ci sono anche alcune complicazioni riguardo al fatto che gli invii abbiano un attributo di valore non predefinito IIRC.

Il punto da togliere è che non esiste uno standard definito per ciò che accade qui ed è interamente per capriccio del browser - per quanto possibile in qualsiasi cosa tu stia facendo, cerca di evitare di fare affidamento su un comportamento particolare. Se davvero devi saperlo, puoi probabilmente scoprire il comportamento delle varie versioni del browser, ma quando ho investigato questo tempo fa c'erano alcune condizioni piuttosto contorte (che ovviamente sono soggette a modifiche con le nuove versioni del browser) e ti consiglierei per evitarlo se possibile!


1
Per quanto riguarda il paragrafo 2: la mia domanda di base era se ci fosse qualcosa in qualche specifica all'effetto di "Se il browser fornisce un mezzo per inviare un modulo senza specificare un controllo di invio ...". Ma ho capito dalla risposta di David che non c'è. Il mio punto su IE era che a volte premendo Invio si invia un modulo e non si imposta alcun pulsante di invio. Una conseguenza è che, se si hanno più moduli che inviano allo stesso script, non è possibile fare affidamento sui pulsanti di invio per distinguerli. Questo è emerso dal progetto a cui sto lavorando.
Stewart,

1
Sezione del primo paragrafo molto utile: grazie.
rbassett,

63

HTML 4 non lo rende esplicito. L'attuale bozza di lavoro HTML5 specifica che il primo pulsante di invio deve essere predefinito :

Un formpulsante di default dell'elemento è il primo pulsante di invio in ordine albero il cui proprietario del modulo è che formelemento.

Se i supporti user agent lasciando l'utente inviare un modulo in modo implicito (ad esempio, su alcune piattaforme colpire il tasto "Enter", mentre un campo di testo è focalizzato implicitamente invia il modulo), quindi farlo per una forma il cui pulsante di default ha un definito di attivazione il comportamento deve indurre l'agente utente a eseguire passaggi di attivazione di clic sintetici su quel pulsante predefinito .


Ok, quindi è quello che dovrebbe fare. Posso usare?
Pacerier,

Sono contento di vedere "invio implicito" in HTML5.
Clint Pachl,

61

Andrezj ha praticamente capito bene ... ma ecco una semplice soluzione cross-browser.

Prendi una forma come questa:

<form>
    <input/>
    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>

    <button type="submit" value="default action"/>
</form>

e refactoring a questo:

<form>
    <input/>

    <button style="overflow: visible !important; height: 0 !important; width: 0 !important; margin: 0 !important; border: 0 !important; padding: 0 !important; display: block !important;" type="submit" value="default action"/>

    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>
    <button type="submit" value="still another non-default action"/>

    <button type="submit" value="default action"/>
</form>

Dato che le specifiche del W3C indicano che sono validi più pulsanti di invio, ma omette le indicazioni su come gestirli l'utente-agente, i produttori di browser sono lasciati implementare come meglio credono. Ho scoperto che invieranno il primo pulsante di invio nel modulo o invieranno il pulsante di invio successivo dopo il campo del modulo attualmente attivo.

Sfortunatamente, semplicemente aggiungendo uno stile di visualizzazione: nessuno; non funzionerà perché le specifiche del W3C indicano che qualsiasi elemento nascosto deve essere escluso dalle interazioni dell'utente. Quindi nascondilo in bella vista invece!

Sopra è un esempio della soluzione che ho finito per mettere in produzione. Se si preme il tasto Invio, l'invio del modulo predefinito comporta il comportamento previsto, anche quando sono presenti altri valori non predefiniti e precede il pulsante di invio predefinito nel DOM. Bonus per l'interazione mouse / tastiera con input utente espliciti evitando gestori javascript.

Nota: la tabulazione attraverso il modulo non visualizzerà lo stato attivo per nessun elemento visivo ma causerà comunque la selezione del pulsante invisibile. Per evitare questo problema, imposta semplicemente gli attributi tabindex di conseguenza e ometti un attributo tabindex sul pulsante di invio invisibile. Sebbene possa sembrare fuori luogo promuovere questi stili in! Important, dovrebbero impedire a qualsiasi framework o stili di pulsanti esistenti di interferire con questa correzione. Inoltre, quegli stili in linea sono decisamente scadenti, ma stiamo provando concetti qui ... non scrivendo codice di produzione.


5
Grazie. Inciampato sul display: nessun problema. Invece di ridurre a icona il pulsante, puoi anche spostarlo fuori dalla pagina circondandolo con un <div style="position: fixed; left: -1000px; top: -1000px />. Ancora un'altra cosa da preoccupare: ridurre al minimo o allontanare il pulsante dal flusso di pagine con CSS potrebbe far emergere problemi di WAI, perché gli screen reader vedranno comunque il pulsante predefinito.
Stefan Haberl,

2
GRAZIE @James per questa risposta dettagliata.
Nathan,

1
questo ha funzionato per me, grazie. Ho dovuto aggiungere questo per il bordo del pulsante: nessuno; per farlo sparire completamente
Macumbaomuerte,

4
Puoi semplicemente impostare l'attributo tabindex del pulsante nascosto su -1
tvanc

2
A cosa <input/>serve lassù?
Sz.

16

Penso che questo post sarebbe di aiuto se qualcuno volesse farlo con jQuery:

http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/

La soluzione di base è:

$(function() {
    $("form input").keypress(function (e) {
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        $('input[type=submit].default').click();
        return false;
    } else {
        return true;
    }
    });
});

e un altro mi è piaciuto:

jQuery(document).ready(function() {
$("form input, form select").live('keypress', function (e) {
if ($(this).parents('form').find('button[type=submit].default, input[type=submit].default').length <= 0)
return true;

if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$(this).parents('form').find('button[type=submit].default, input[type=submit].default').click();
return false;
} else {
return true;
}
});
}); 

jQuery.Event ha sempre il suo .wichattributo. Inoltre, non è necessario ricorrere a DOM .keyCode(o del .charCoderesto).
Arjan,

Un altro problema relativo a jQuery qui è la doppia query inutile. Poiché non è necessario restituire true, inoltre, la versione jQuery diventa molto chiara e completa sull'integrazione delle riduzioni consigliate da Arjan in precedenza.
soletan,

Ho usato il keydown invece del keypress (evita di aspettare il keyup) e l'ho aggiunto e.preventDefault();all'inizio di questa funzione per evitare l'esecuzione del pulsante predefinito "reale". Funziona davvero bene.
Matt Roy,

6

Avevo un modulo con 11 pulsanti di invio su di esso e avrebbe sempre usato il primo pulsante di invio quando l'utente ha premuto invio. Ho letto altrove che non è una buona idea (cattiva pratica) avere più di un pulsante di invio in un modulo e il modo migliore per farlo è avere il pulsante desiderato come predefinito, come unico pulsante di invio nel modulo. Gli altri pulsanti dovrebbero essere trasformati in "TYPE = BUTTON" e aggiungere un evento onClick che chiama la tua routine di invio in Javascript. Qualcosa come questo :-

<SCRIPT Language="JavaScript">
function validform()
{
  // do whatever you need to validate the form, and return true or false accordingly
}

function mjsubmit()
{
  if (validform()) { document.form1.submit(); return true;}
  return false;
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="button1" VALUE="button1" onClick="document.form1.submitvalue='button1'; return mjsubmit();">
<INPUT TYPE=BUTTON NAME="button2" VALUE="button2" onClick="document.form1.submitvalue='button2'; return mjsubmit();">
<INPUT TYPE=SUBMIT NAME="button3" VALUE="button3" onClick="document.form1.submitvalue='button3'; return validform();">
<INPUT TYPE=BUTTON NAME="button4" VALUE="button4" onClick="document.form1.submitvalue='button4'; return mjsubmit();">

Qui, button3 è il valore predefinito e sebbene si stia inviando a livello di codice il modulo con gli altri pulsanti, la routine mjsubmit li convalida. HTH.


19
Cattiva idea. Il modulo non funzionerà con JS disabilitato. JS dovrebbe essere usato in modo discreto.
BalusC

7
Pochissimi browser hanno JS disattivato per impostazione predefinita, anche quelli su iPod! Sul modulo che stavo citando, JS off lo renderebbe inutile! Tante cerniere su JS in esecuzione.
grafico

7
Disattivato per impostazione predefinita o meno, coloro che hanno disabilitato JS non devono accenderlo solo per aggirare un piccolo inconveniente così sciocco come questo.
Stewart,

2
che tipo di modulo ha 11 pulsanti di invio ?? ( curiosità )
Ben

2
Il motivo principale per cui vedo la convalida di Javascript discreto è che Javascript invadente tende ad essere complicato. Non sono sicuro di come qualificare ciò che sto pensando, ma quando vedo pagine totalmente dipendenti da JS, sto anche scommettendo che posso fare alcune cose difficili con il mio DOM e fare qualcosa di non intenzionale sul server.
Samantha Branham,

6

Questo ora può essere risolto usando flexbox:

HTML

<form>
    <h1>My Form</h1>
    <label for="text">Input:</label>
    <input type="text" name="text" id="text"/>

    <!-- Put the elements in reverse order -->
    <div class="form-actions">
        <button>Ok</button> <!-- our default action is first -->
        <button>Cancel</button>
    </div>
</form>

CSS

.form-actions {
    display: flex;
    flex-direction: row-reverse; /* reverse the elements inside */
}

Spiegazione
Utilizzando la casella flessibile, possiamo invertire l'ordine degli elementi in un contenitore che utilizza display: flexanche utilizzando la regola CSS:flex-direction: row-reverse . Ciò non richiede CSS o elementi nascosti. Per i browser meno recenti che non supportano la flexbox, ottengono comunque una soluzione praticabile ma gli elementi non verranno invertiti.

Demo
http://codepen.io/Godwin/pen/rLVKjm


2

Ho avuto difficoltà con la stessa domanda da quando avevo il pulsante di invio nel mezzo del da cui reindirizzato invia a un'altra pagina, in questo modo:

<button type="submit" onclick="this.form.action = '#another_page'">More</button>

Quando l'utente ha premuto il tasto Invio, è stato fatto clic su questo pulsante anziché su un altro pulsante di invio.

Quindi ho fatto alcuni test primitivi creando un da con più pulsanti di invio e diverse opzioni di visibilità e avvisi di eventi onclick su quale pulsante è stato fatto clic: https://jsfiddle.net/aqfy51om/1/

Browser e sistemi operativi utilizzati per i test:

FINESTRE

  • Google Chrome 43 (dai google: D)
  • Mozilla Firefox 38
  • Internet Explorer 11
  • Opera 30.0

OSX

  • Google Chrome 43
  • Safari 7.1.6

La maggior parte di questi browser ha fatto clic sul primo pulsante nonostante le opzioni di visibilità applicate eccetto IE e Safari che hanno fatto clic sul terzo pulsante, che è "visibile" all'interno del contenitore "nascosto":

<div style="width: 0; height: 0; overflow: hidden;">
    <button type="submit" class="btn btn-default" onclick="alert('Hidden submit button #3 was clicked');">Hidden submit button #3</button>
</div>

Quindi il mio suggerimento, che ho intenzione di usare me stesso, è:

Se il modulo ha più pulsanti di invio con significato diverso, quindi includere il pulsante di invio con azione predefinita all'inizio del modulo che è:

  1. Completamente visibile
  2. Avvolto in un contenitore con style="width: 0; height: 0; overflow: hidden;"

MODIFICA Un'altra opzione potrebbe essere quella di compensare il pulsante (sempre all'inizio del da) style="position: absolute; left: -9999px; top: -9999px;", appena provato in IE - ha funzionato, ma non ho idea di cos'altro possa rovinare, ad esempio la stampa ..


1

Dai tuoi commenti:

Una conseguenza è che, se si hanno più moduli che inviano allo stesso script, non è possibile fare affidamento sui pulsanti di invio per distinguerli.

Lascio cadere un <input type="hidden" value="form_name" />in ogni modulo.

Se invii con JavaScript: aggiungi gli eventi di invio ai moduli, non fai clic sugli eventi nei loro pulsanti. Gli utenti di Saavy non toccano il mouse molto spesso.


Anzi, ma questo fa sorgere questa domanda: stackoverflow.com/questions/541869/…
Stewart,

1

Quando si hanno più pulsanti di invio in un singolo modulo e un utente preme il tasto INVIO per inviare il modulo da un campo di testo, questo codice sovrascrive la funzionalità predefinita, chiamando l'evento di invio sul modulo dall'evento di pressione del tasto. Ecco quel codice:

$('form input').keypress(function(e){

    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ $(e.target).closest('form').submit(); return false; }
    else return true;

});

Semplice e risolve il problema
toddmo

1

È strano che il primo pulsante Invio vada sempre al primo pulsante, indipendentemente dal fatto che sia visibile o meno, ad esempio utilizzando jquery show/hide(). L'aggiunta di un attributo .attr('disabled', 'disabled')impedisce di ricevere completamente il pulsante Invio. È un problema ad esempio quando si regola la visibilità del pulsante Inserisci / Modifica + Elimina nelle finestre di dialogo dei record. Ho trovato meno hacking e semplice posizionando Modifica davanti a Inserisci

<button type="submit" name="action" value="update">Update</button>
<button type="submit" name="action" value="insert">Insert</button>
<button type="submit" name="action" value="delete">Delete</button>

e usa il codice javascript:

$("#formId button[type='submit'][name='action'][value!='insert']").hide().attr('disabled', 'disabled');
$("#formId button[type='submit'][name='action'][value='insert']").show().removeAttr('disabled');

0

la mia ricetta:

<form>
<input type=hidden name=action value=login><!-- the magic! -->

<input type=text name=email>
<input type=text name=password>

<input type=submit name=action value=login>
<input type=submit name=action value="forgot password">
</form>

Invierà il campo nascosto predefinito se nessuno dei pulsanti viene "cliccato".

se vengono cliccati, hanno la preferenza e il valore viene passato.


2
Ma questo comportamento è specificato dallo standard? E i browser possono essere attendibili per implementarlo correttamente?
Stewart

buona domanda. l'ho testato per funzionare su tutti i browser A (dalla matrice del browser yui) ed è il più coerente che potrei ottenere nella vita reale (indipendentemente da ciò che gli standard specificano)
gcb

@yellowandred cosa succede? daremo un'occhiata più tardi
gcb,

1
errore mio, ho cambiato {type = "hidden"} e non ho notato gli stessi valori di "nome".
Giallo e rosso,

Questo non funziona per me in IE11 o Fx30. Il valore è sempre impostato sul valore nascosto.
Jamie Kitson,

0

Un'altra soluzione che ho usato è quella di avere solo un pulsante nel modulo e falsificare gli altri pulsanti.

Ecco un esempio:

<form>
  <label for="amount">Amount of items</label>
  <input id="amount" type="text" name="amount" />
  <span id="checkStock" class="buttonish">Check stock</span>
  <button type="submit" name="action" value="order">Place order</button>
</form>

Dopodiché modifico gli elementi di span in modo che appaiano come un pulsante. Un listener JS osserva l'intervallo ed esegue l'operazione desiderata una volta cliccato.

Non necessariamente adatto a tutte le situazioni, ma almeno è abbastanza facile da fare.


1
Qual è il fallback per gli utenti che hanno disabilitato JS?
Stewart,

Gli utenti con JS disabilitato non saranno in grado di utilizzare Internet, è così semplice al giorno d'oggi.
Christoffer Bubach,

0

Dalle specifiche HTML 4 :

Se un modulo contiene più di un pulsante di invio, solo il pulsante di invio attivato ha esito positivo.

Ciò significa che dato più di 1 pulsante di invio e nessuno attivato (cliccato), nessuno dovrebbe avere successo.

E direi che questo ha senso: immagina un modulo enorme con più pulsanti di invio. Nella parte superiore, c'è un pulsante "elimina questo record", quindi seguono molti input e in basso c'è un pulsante "aggiorna questo record". Un utente che preme invio mentre si trova in un campo nella parte inferiore del modulo non sospetterebbe mai di aver implicitamente colpito "elimina questo record" dall'alto.

Pertanto penso che non sia una buona idea utilizzare il primo o qualsiasi altro pulsante che l'utente non definisce (fare clic). Tuttavia, i browser lo stanno facendo ovviamente.


-2

EDIT: Scusa, quando ho scritto questa risposta stavo pensando di inviare pulsanti in senso generale. La risposta di seguito non riguarda più type="submit"pulsanti, in quanto lascia solo uno type="submit"e cambia l'altro in type="button". Lascio la risposta qui come riferimento nel caso in cui qualcuno aiuti a modificarlo typenella sua forma:

Per determinare quale pulsante viene premuto quando si preme invio, è possibile contrassegnarlo con type="submit"e gli altri pulsanti contrassegnarli con type="button". Per esempio:

<input type="button" value="Cancel" />
<input type="submit" value="Submit" />

Digitare "pulsante" non causa l'invio del modulo. Viene utilizzato solo per attivare gli script lato client.
Stewart,

esattamente, ecco perché il browser lo salta quando si preme invio e viene eseguito quello con il tipo "submit". È possibile utilizzare quello con il tipo "pulsante" per fare qualsiasi altra cosa al clic, ad esempio. Rimuovi il voto negativo.
Jesús Carrera,

La domanda riguardava più pulsanti di invio .
Stewart,

Il mio esempio è totalmente valido per più pulsanti di invio. Quello con il tipo "submit" è quello determinato dal browser per agire come premuto (che è di cosa si trattava la domanda). Quindi con l'altro pulsante puoi usarlo come pulsante di invio e usare eventi JavaScript come l'evento onClick che hai nel tuo esempio. Quindi la mia risposta è pertinente e non merita un voto negativo. Per favore rimuovilo.
Jesús Carrera,

1
Se il tuo punto era suggerire di rimuovere l'ambiguità facendo solo uno di loro, digita "invia" e utilizza JavaScript per implementare gli altri pulsanti, allora questo è un duplicato della risposta del grafico e come tale è già stato respinto come una cattiva idea.
Stewart,
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.