web-dev-qa-db-fra.com

Comment le bouton d'envoi par défaut d'un formulaire HTML est-il déterminé?

Si un formulaire est soumis mais pas par un bouton spécifique, tel que

  • en appuyant Enter
  • en utilisant HTMLFormElement.submit() dans JS

comment un navigateur est-il censé déterminer lequel des multiples boutons de soumission, le cas échéant, doit être utilisé?

Ceci est significatif à deux niveaux:

  • appel d'un gestionnaire d'événement onclick attaché à un bouton d'envoi
  • les données renvoyées au serveur Web

Mes expériences jusqu'à présent ont montré que:

  • en appuyant sur Enter, Firefox, Opera et Safari utilisent le premier bouton d'envoi du formulaire
  • en appuyant sur Enter, IE utilise soit le premier bouton d'envoi, soit aucun bouton, selon les conditions que je n'ai pas pu comprendre.
  • tous ces navigateurs n'en utilisent aucun pour un JS submit

Que dit la norme?

Si cela peut vous aider, voici mon code de test (le PHP ne concerne que ma méthode de test, pas ma question elle-même)

<!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>
199
Stewart

Si vous soumettez le formulaire via Javascript (c'est-à-dire formElement.submit() ou quelque chose d'équivalent), alors aucun des boutons d'envoi n'est considéré comme ayant abouti et aucun de leurs les valeurs sont incluses dans les données soumises. (Notez que si vous soumettez le formulaire à l’aide de submitElement.click(), la soumission à laquelle vous avez fait référence est considérée comme active; cela n’entre pas vraiment dans le champ de votre question car ici le bouton de soumission est sans ambiguïté, mais j’ai pensé Je l’incluerais pour ceux qui liraient la première partie et me demanderais comment réussir un bouton de soumission via la soumission de formulaire JS. Bien sûr, les gestionnaires du formulaire onsubmit continueront à être déclenchés de cette façon alors qu’ils ne le feraient pas via form.submit() alors c'est une autre bouilloire de poisson ...)

Si le formulaire est soumis en appuyant sur Entrée alors que vous vous trouvez dans un champ non textarea, c'est à l'agent utilisateur de décider ce qu'il veut ici. Les specs ne disent rien sur la soumission d'un formulaire à l'aide de la touche Entrée lorsque vous vous trouvez dans un champ de saisie de texte (si vous appuyez sur un bouton et activez-le à l'aide d'un espace ou autre, il n'y a donc aucun problème bouton d'envoi est utilisé sans ambiguïté). Tout ce qu’il dit, c’est qu’un formulaire doit être soumis lorsqu’un bouton de soumission est activé. Il n’est même pas nécessaire de cliquer sur Entrée, par exemple. une saisie de texte soumettra le formulaire.

Je pense qu'Internet Explorer choisit le bouton d'envoi qui apparaît en premier dans le source. J'ai le sentiment que Firefox et Opera choisissent le bouton avec le tabindex le plus bas, revenant au premier défini si rien d'autre n'est défini. Il existe également certaines complications quant à la question de savoir si les soumissions ont un attribut de valeur autre que la valeur par défaut IIRC.

Ce qu'il faut retenir, c'est qu'il n'y a pas de norme définie pour ce qui se passe ici et que cela dépend entièrement du navigateur. Par conséquent, essayez d'éviter, dans la mesure du possible, tout comportement que vous fassiez. Si vous devez vraiment savoir, vous pouvez probablement connaître le comportement des différentes versions du navigateur, mais lorsque j’en ai enquêté il y a un certain temps, certaines conditions étaient assez compliquées (qui sont bien sûr susceptibles de changer avec les nouvelles versions du navigateur) et je le conseillerais. à éviter si possible!

109
Andrzej Doyle

Andrezj a tout à fait compris ... mais voici une solution simple pour tous les navigateurs.

Prenez une forme comme celle-ci:

<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>

et refactor à ceci:

<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>

Etant donné que la spécification W3C indique que plusieurs boutons de soumission sont valides, mais ne donne aucune indication sur la manière dont l'agent utilisateur doit les gérer, les fabricants de navigateurs sont libres de les implémenter à leur guise. J'ai constaté qu'ils soumettraient le premier bouton d'envoi du formulaire ou le prochain bouton d'envoi après le champ de formulaire actuellement actif.

Malheureusement, ajouter simplement un style de display: none; ne fonctionnera pas car la spécification W3C indique que tout élément masqué doit être exclu des interactions utilisateur. Alors cachez-le à la vue!

Ci-dessus, un exemple de la solution que j'ai finalement mise en production. Le fait d'appuyer sur la touche Entrée déclenche le comportement par défaut du formulaire par défaut, même lorsque d'autres valeurs autres que celles par défaut sont présentes et précédent le bouton d'envoi par défaut du DOM. Bonus pour l'interaction souris/clavier avec des entrées utilisateur explicites tout en évitant les gestionnaires javascript.

Remarque: la tabulation du formulaire n’affichera le focus pour aucun élément visuel, mais le bouton invisible sera toujours sélectionné. Pour éviter ce problème, définissez simplement les attributs tabindex en conséquence et omettez un attribut tabindex sur le bouton de soumission invisible. Bien qu'il puisse sembler hors de propos de promouvoir ces styles en! Important, ils devraient empêcher tout type de cadre ou de style de bouton existant d'interférer avec ce correctif. En outre, ces styles en-ligne sont définitivement médiocres, mais nous prouvons des concepts ici ... pas en écrivant du code de production.

60
James

HTML 4 ne le rend pas explicite. Le brouillon de travail HTML5 actuel spécifie que le premier bouton d'envoi doit être le bouton par défaut :

Le bouton par défaut d'un élément form est le premier bouton d'envoi dans ordre d'arborescence dont propriétaire du formulaire est cet élément form.

Si l'agent utilisateur prend en charge le fait de permettre à l'utilisateur de soumettre un formulaire implicitement (par exemple, sur certaines plates-formes, appuyer sur la touche "Entrée" alors qu'un champ de texte est activé de manière implicite), le faire pour un formulaire dont bouton par défaut a défini comportement d'activation doit obliger l'agent utilisateur à exécuter les étapes d'activation de clic synthétique sur celui-ci bouton par défaut .

58
Quentin

Je pense que ce post aiderait si quelqu'un veut le faire avec jQuery:

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

La solution de base est:

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

et un autre que j'ai aimé était:

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;
}
});
}); 
16
Rodrigo Caballero

J'avais un formulaire avec 11 boutons de soumission et il utilisait toujours le premier bouton de soumission lorsque l'utilisateur appuyait sur Entrée. J'ai lu ailleurs que ce n'est pas une bonne idée (mauvaise pratique) d'avoir plus d'un bouton d'envoi sur un formulaire, et la meilleure façon de le faire est d'avoir le bouton que vous voulez par défaut, en tant que seul bouton d'envoi du formulaire. Les autres boutons doivent être transformés en "TYPE = BUTTON" et un événement onClick ajouté appelle votre propre routine de soumission en Javascript. Quelque chose comme ça :-

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

Ici, button3 est la valeur par défaut et bien que vous soumettiez le formulaire avec les autres boutons par programme, la routine mjsubmit les valide. HTH.

6
graphic

Ceci peut maintenant être résolu en utilisant 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 */
}

Explication
En utilisant flex box, nous pouvons inverser l’ordre des éléments d’un conteneur qui utilise display: flex en utilisant également la règle CSS: flex-direction: row-reverse. Cela ne nécessite aucun élément CSS ou caché. Pour les navigateurs plus anciens qui ne prennent pas en charge flexbox, ils obtiennent toujours une solution viable mais les éléments ne seront pas inversés.

Démo
http://codepen.io/Godwin/pen/rLVKjm

5
Godwin

J'ai eu du mal avec la même question depuis que j'avais le bouton de soumission au milieu de la rediriger soumettre à une autre page, comme suit:

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

Lorsque l'utilisateur a appuyé sur la touche Entrée, ce bouton a été sélectionné au lieu d'un autre bouton d'envoi.

J'ai donc fait quelques tests primitifs en créant un avec plusieurs boutons de soumission, différentes options de visibilité et un événement onclick indiquant quel bouton était cliqué: https://jsfiddle.net/aqfy51om/1/

Navigateurs et systèmes d'exploitation utilisés pour les tests:

WINDOWS

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

OSX

  • Google Chrome 43
  • Safari 7.1.6

La plupart de ces navigateurs ont cliqué sur le premier bouton en dépit des options de visibilité appliquées sauf IE et Safari qui ont cliqué sur le troisième bouton, qui est "visible" à l'intérieur de "masqué" récipient:

<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>

Donc, ma suggestion, que je vais utiliser moi-même, est la suivante:

Si votre formulaire comporte plusieurs boutons de soumission ayant une signification différente, incluez le bouton de soumission avec l'action par défaut au début du formulaire, à savoir:

  1. Entièrement visible
  2. Enveloppé dans un conteneur avec style="width: 0; height: 0; overflow: hidden;"

EDIT Une autre option pourrait être de décaler le bouton (toujours au début du début) style="position: absolute; left: -9999px; top: -9999px;", juste essayé dans IE - travaillé, mais je ne sais pas quoi d'autre il peut bousiller, par exemple l'impression ..

2
Kristian

Lorsque vous avez plusieurs boutons de soumission dans un seul formulaire et qu'un utilisateur appuie sur la touche Entrée pour soumettre le formulaire à partir d'un champ de texte, ce code remplace la fonctionnalité par défaut en appelant l'événement de soumission sur le formulaire à partir de l'événement de pression. Voici ce code:

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

});
1
axiom82

De vos commentaires:

Conséquence: si plusieurs formulaires sont soumis au même script, vous ne pouvez pas vous fier aux boutons de soumission pour les distinguer.

Je dépose un <input type="hidden" value="form_name" /> dans chaque formulaire.

Si vous soumettez avec javascript: ajoutez des événements de soumission aux formulaires, ne cliquez pas sur les événements pour leurs boutons. Les utilisateurs de Saavy ne touchent pas leur souris très souvent.

1
Ryan Florence

Étrange que le premier bouton Entrée passe toujours au premier bouton, qu'il soit visible ou non, par ex. en utilisant jquery show/hide(). L'ajout de l'attribut .attr('disabled', 'disabled') empêche la réception du bouton Enter submit complètement. C'est un problème par exemple lors du réglage Insérer/Modifier + Supprimer visibilité des boutons dans les boîtes de dialogue d'enregistrement. J'ai trouvé moins de place et de placement simple Edit devant Insert

<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>

et utilisez le code javascript:

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

De la HTML 4 spec :

Si un formulaire contient plus d'un bouton d'envoi, seul le bouton d'envoi activé a réussi.

Cela signifie que pour plus d'un bouton d'envoi et qu'aucun n'est activé (cliqué), aucun ne devrait réussir.

Et je dirais que cela a du sens: Imaginez un formulaire énorme avec plusieurs boutons de soumission. En haut, il y a un bouton "supprimer cet enregistrement", puis de nombreuses entrées suivent et en bas, un bouton "mettre à jour cet enregistrement". Un utilisateur qui clique sur entrer alors qu'il se trouve dans un champ au bas du formulaire ne soupçonnera jamais qu'il clique implicitement sur "supprimer cet enregistrement" à partir du haut.

Par conséquent, je pense que ce n’est pas une bonne idée d’utiliser le premier ou un autre bouton si l’utilisateur ne le définit pas (cliquez). Néanmoins, les navigateurs le font bien sûr.

0
Christopher K.

ma recette:

<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>

Il enverra le champ caché par défaut si aucun des boutons n'est "cliqué".

si on clique dessus, ils ont la préférence et sa valeur est transmise.

0
gcb

Une autre solution que j'ai utilisée consiste à ne créer qu'un seul bouton dans le formulaire et à simuler les autres boutons.

Voici un exemple:

<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>

Je stylise ensuite les éléments span pour qu'ils ressemblent à un bouton. Un écouteur JS observe l'étendue et effectue l'opération souhaitée une fois cliqué.

Pas nécessairement approprié pour toutes les situations, mais au moins c'est assez facile à faire.

0
Johan Fredrik Varen