250 votes

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 sur Enter
  • en utilisant HTMLFormElement.submit() dans JS

comment un navigateur est-il censé déterminer lequel des multiples boutons d'envoi, le cas échéant, doit être utilisé comme celui sur lequel on a appuyé ?

Ceci est significatif à deux niveaux :

  • en appelant un onclick gestionnaire d'événement 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, en fonction de conditions que je n'ai pas réussi à déterminer.
  • tous ces navigateurs n'en utilisent aucun pour une soumission JS

Que dit la norme ?

Si cela peut vous aider, voici mon code de test (le PHP n'est pertinent que pour ma méthode de test, pas pour 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>

129voto

Andrzej Doyle Points 52541

Si vous soumettez le formulaire via JavaScript (c'est-à-dire, formElement.submit() ou quelque chose d'équivalent), alors aucun des boutons d'envoi sont considérés comme réussis et aucune de leurs valeurs n'est incluse dans les données envoyées. (Notez que si vous soumettez le formulaire en utilisant le bouton submitElement.click() alors le bouton submit auquel vous faisiez référence est considéré comme actif ; cela n'entre pas vraiment dans le cadre de votre question puisque ici le bouton submit est sans ambiguïté mais j'ai pensé l'inclure pour les personnes qui lisent la première partie et se demandent comment faire réussir un bouton submit via un formulaire JavaScript. Bien sûr, les gestionnaires onsubmit du formulaire se déclencheront toujours de cette façon, alors qu'ils ne le feraient pas via le bouton "submit". form.submit() alors c'est une autre paire de manches...)

Si le formulaire est soumis en appuyant sur la touche Entrée alors qu'il se trouve dans un champ non textuel, c'est en fait à l'agent utilisateur de décider ce qu'il veut. Les spécifications ne disent rien sur la soumission d'un formulaire à l'aide de la fonction Enter dans un champ de saisie de texte (si vous passez à un bouton et l'activez en utilisant l'espace ou autre, il n'y a pas de problème car ce bouton d'envoi spécifique est utilisé sans ambiguïté). Tout ce qui est dit, c'est qu'un formulaire doit être soumis lorsqu'un bouton d'envoi est activé. Il n'est même pas nécessaire que l'activation d'un bouton d'envoi soit obligatoire. Enter par exemple, une entrée de texte soumettra le formulaire.

Je crois qu'Internet Explorer choisit le bouton submit qui apparaît en premier dans la source ; j'ai l'impression que Firefox et Opera choisissent le bouton avec le tabindex le plus bas, en revenant au premier défini si rien d'autre n'est défini. Il y a également quelques complications concernant le fait que les boutons d'envoi aient un attribut de valeur autre que celui par défaut, je crois.

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 c'est entièrement à la merci du navigateur - donc, autant que possible, dans tout ce que vous faites, essayez d'éviter de vous fier à un comportement particulier. Si vous voulez vraiment savoir, vous pouvez probablement trouver le comportement des différentes versions du navigateur, mais lorsque j'ai enquêté sur ce sujet il y a quelque temps, il y avait des conditions assez alambiquées (qui sont bien sûr susceptibles de changer avec les nouvelles versions du navigateur) et je vous conseille d'éviter cela si possible !

2 votes

Concernant le paragraphe 2 : ma question de base était de savoir s'il y a quelque chose dans une spécification à l'effet de "Si le navigateur fournit un moyen de soumettre un formulaire sans spécifier un contrôle de soumission...". Mais je déduis de la réponse de David que ce n'est pas le cas. Ce que je voulais dire à propos d'IE, c'est que parfois, le fait d'appuyer sur Entrée soumet un formulaire sans qu'aucun bouton d'envoi ne soit activé. Une conséquence est que, si vous avez plusieurs formulaires qui se soumettent au même script, vous ne pouvez pas compter sur les boutons de soumission pour les distinguer. Ce problème est apparu dans le projet sur lequel je travaille.

1 votes

Section de la fourchette du premier paragraphe très utile - merci.

82voto

Quentin Points 325526

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

A [form](https://www.w3.org/TR/html5/forms.html#the-form-element) Le bouton par défaut de l'élément est le premier bouton d'envoi sur ordre des arbres dont propriétaire du formulaire c'est que [form](https://www.w3.org/TR/html5/forms.html#the-form-element) élément.

Si l'agent utilisateur permet de laisser l'utilisateur soumettre un formulaire implicitement (par exemple, sur certaines plates-formes, le fait d'appuyer sur la touche "entrée alors qu'un champ de texte est centré soumet implicitement le formulaire), alors le faire pour un formulaire dont bouton par défaut a une définition comportement de déclenchement doit amener l'agent utilisateur à exécuter les étapes de l'activation par clic synthétique sur ce point bouton par défaut .

0 votes

Ok, donc c'est ce que c'est censé faire. Je peux l'utiliser ?

0 votes

Je suis heureux de voir la "soumission implicite" en HTML5.

0 votes

@user5480949 - Vrai, mais pas pertinent pour la question.

67voto

James Points 200

Réponse d'Andrezj J'ai presque tout compris... mais voici une solution facile pour les navigateurs croisés.

Prenez un formulaire comme celui-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 refactoriser à 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>

Depuis le W3C indique que les boutons d'envoi multiples sont valides, mais omet de donner des indications sur la manière dont l'agent utilisateur doit les traiter, les fabricants de navigateurs étant laissés libres de les mettre en œuvre comme bon leur semble. J'ai constaté qu'ils soumettent soit le premier bouton d'envoi du formulaire, soit le bouton d'envoi suivant le champ du formulaire qui a actuellement le focus.

Malheureusement, le simple fait d'ajouter un style de affichage : aucun ; ne fonctionnera pas car la spécification du W3C indique que tout élément caché doit être exclu des interactions avec l'utilisateur. Cachez-le plutôt à la vue de tous !

Ci-dessus, vous trouverez un exemple de la solution que j'ai fini par mettre en production. L'appui sur la touche Entrée déclenche l'envoi du formulaire par défaut comme prévu, même lorsque d'autres valeurs non par défaut sont présentes et précèdent le bouton d'envoi par défaut dans le DOM. Bonus pour l'interaction souris/clavier avec des entrées utilisateur explicites tout en évitant les gestionnaires JavaScript.

Remarque : le fait d'utiliser la fonction de tabulation dans le formulaire n'affichera le focus d'aucun élément visuel, mais entraînera tout de même la sélection du bouton invisible. Pour éviter ce problème, il suffit de définir les attributs tabindex en conséquence et d'omettre un attribut tabindex sur le bouton d'envoi invisible. Bien qu'il puisse sembler déplacé de promouvoir ces styles à !important, ils devrait empêcher tout cadre ou style de bouton existant d'interférer avec cette correction. De plus, ces styles en ligne sont définitivement de mauvais goût, mais nous sommes en train de prouver des concepts ici... pas d'écrire du code de production.

5 votes

Merci. Je suis tombé sur le affichage : aucun également le problème. Au lieu de minimiser le bouton, vous pouvez également le déplacer hors de la page en l'entourant d'une balise <div style="position: fixed; left: -1000px; top: -1000px /> . Encore une chose à prendre en compte : Le fait de minimiser ou d'éloigner le bouton du flux de la page à l'aide d'une CSS peut poser des problèmes de WAI, car les lecteurs d'écran verront toujours le bouton par défaut.

2 votes

MERCI @James pour cette réponse détaillée.

1 votes

Ça a marché pour moi, merci. J'ai dû ajouter ceci pour le bouton border:none ; pour qu'il disparaisse complètement.

17voto

Rodrigo Caballero Points 458

Je pense que ce post pourrait aider 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 la suivante :

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

0 votes

jQuery.Event a toujours son .wich attribut. Il n'est pas non plus nécessaire de recourir à l'attribut DOM. .keyCode (o .charCode d'ailleurs).

0 votes

Un autre problème concernant jQuery est la double requête inutile. Puisqu'il n'y a pas besoin de retourner true, en plus, la version jQuery devient vraiment claire et courte sur les réductions d'intégration conseillées par Arjan auparavant.

0 votes

J'ai utilisé keydown au lieu de keypress (pour éviter d'attendre keyup) et j'ai ajouté e.preventDefault(); au début de cette fonction pour éviter l'exécution du "vrai" bouton par défaut. Cela fonctionne très bien.

7voto

graphic Points 92

J'avais un formulaire avec 11 boutons d'envoi, et il utilisait toujours le premier bouton d'envoi lorsque l'utilisateur appuyait sur la touche Enter . 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 que la meilleure façon de faire est d'avoir le bouton que vous voulez par défaut, comme le seul bouton d'envoi sur le formulaire. Les autres boutons doivent être transformés en "TYPE=BUTTON" et un événement onClick doit être ajouté pour appeler votre propre routine d'envoi en JavaScript. Quelque chose comme ceci :

<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, le bouton3 est le bouton par défaut, et bien que vous soumettiez le formulaire de manière programmatique avec les autres boutons, le bouton mjsubmit la routine les valide.

23 votes

Mauvaise idée. Votre formulaire ne fonctionnera pas si le JS est désactivé. Le JS doit être utilisé de manière discrète.

7 votes

Très peu de navigateurs ont JS désactivé par défaut, même ceux des iPods ! Sur le formulaire que je citais, la désactivation de JS le rendrait inutile ! Tant de choses dépendent du fonctionnement de JS.

9 votes

Qu'il soit désactivé par défaut ou non, ceux qui ont désactivé JS ne devraient pas avoir à l'activer juste pour contourner un petit problème aussi stupide que celui-ci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X