web-dev-qa-db-fra.com

Action par défaut à exécuter lorsque vous appuyez sur Entrée dans un formulaire

J'ai un formulaire JSF 1.2 avec deux boutons et plusieurs champs de saisie. Le premier bouton ignore les valeurs entrées et remplit la page avec les valeurs d'une base de données, le second bouton enregistre les valeurs entrées. Le problème se produit lorsque l'utilisateur appuie sur Entrée alors que le curseur est dans l'un des champs de saisie, le formulaire est soumis et l'action associée au premier bouton est exécutée.

Le code ressemble à ceci:

<h:commandButton action="#{bean.reset}" value="Reset" />
<h:commandButton action="#{bean.save}" value="Save" />

<!-- h:datatable with several h:inputText elements -->

Est-il possible de déclarer un bouton spécifique comme action par défaut lorsque vous appuyez sur Entrée? Ce comportement est-il réellement spécifié quelque part?

52
Jörn Horstmann

Ceci n'est pas spécifique à JSF. Ceci est spécifique au HTML. La section 4.10.22.2 de la spécification de formulaires HTML5 indique en principe que le premier élément <input type="submit"> qui apparaît dans "l'arborescence" dans le même <form> que l'élément d'entrée actuel dans l'arborescence DOM HTML sera appelé lors de la saisie.

Il existe essentiellement deux solutions de contournement:

  • Utilisez JavaScript pour saisir la touche Entrée et appeler le bouton souhaité.

    <h:form onkeypress="if (event.keyCode == 13) { document.getElementById('formid:saveid').click(); return false; }">
    

    Si vous avez des zones de texte dans le formulaire, vous souhaitez placer le JS sur tous les éléments d'entrée autres que de zones de texte plutôt que sur le formulaire. Voir aussi Empêchez les utilisateurs de soumettre un formulaire en appuyant sur Entrée .


  • Echangez les boutons en HTML et utilisez les flottants CSS pour les échanger.

    <div style="width: 100px; clear: both;">
        <h:commandButton action="#{bean.save}" value="Save" style="float: right;" />
        <h:commandButton action="#{bean.reset}" value="Reset" style="float: left;" />
    </div>
    

    Cela peut ne nécessiter qu'un réglage fin des pixels. Bien sûr, mettez CSS dans son propre fichier .css; utiliser style est une pratique médiocre, l'exemple ci-dessus est pour plus de concision.


Si vous utilisez PrimeFaces, depuis 3.2, vous pouvez utiliser <p:defaultCommand> pour identifier de manière déclarative le bouton qui doit être appelé lorsque vous appuyez sur la touche Entrée du formulaire.

<h:form>
    <p:defaultCommand target="save" />
    ...
    <h:commandButton id="reset" action="#{bean.reset}" value="Reset" />
    <h:commandButton id="save" action="#{bean.save}" value="Save" />
</h:form>

C'est sous la couverture en utilisant JavaScript pour ce qui attache un écouteur keydown au <h:form> parent qui vérifie à son tour si la touche Entrée est enfoncée dans un élément non textarea/button/link, puis appelle click() sur l'élément cible. Fondamentalement identique à la première solution de contournement mentionnée dans cette réponse.

105
BalusC

J'ai trouvé un moyen moins hacky et qui fonctionne bien. L'idée est un commandButton caché.

Malheureusement, le style display:none ne peut pas être utilisé car le commandButton sera ignoré. visibility:hidden n'est pas bon car il garde l'espace du composant réservé.

Mais nous pouvons affiner le style pour que la taille de son l'apparence visuelle sera zéro avec le CSS suivant:

.zeroSize {
    visibility: hidden;
    padding: 0px;
    margin: 0px;
    border: 0px;
    width: 0px;
    height: 0px;
}

Et maintenant, tout ce qu'il faut c'est:

<h:commandButton value="" action="#{bean.save}" class="zeroSize" />

Cela se traduira par un bouton de commande invisible qui peut être activé conformément à la règle premier-prochain-bouton-de-soumission.

9
icza

Pour masquer des éléments, vous pouvez utiliser css: style="visibility: hidden"

Pour modifier l'action par défaut si vous utilisez primefaces, vous pouvez utiliser: <p:defaultCommand target="yourButtonDefault" /> Par exemple:

<h:form id="form">

    <h:panelGrid columns="3" cellpadding="5">
        <h:outputLabel for="name" value="Name:" style="font-weight:bold"/>
        <p:inputText id="name" value="#{defaultCommandBean.text}" />
        <h:outputText value="#{defaultCommandBean.text}" id="display" />
    </h:panelGrid>

    <p:commandButton value="Button1" id="btn1" actionListener="#{defaultCommandBean.btn1Submit}" ajax="false"/>
    <p:commandButton value="Button2" id="btn2" actionListener="#{defaultCommandBean.btn2Submit}" />
    <h:commandButton value="Button3" id="btn3" actionListener="#{defaultCommandBean.btn3Submit}" />

    <p:defaultCommand target="btn3" />

</h:form>

Source: Nouveau composant Primefaces: DefaultCommand

4
Cristian Arteaga

Suivant la recommandation de BalusC de résoudre le problème à l'aide de JavaScript, j'ai écrit du code jQuery pour faire le travail:

$(function(){
  $('form').on('keypress', function(event){
    if(event.which === 13 && $(event.target).is(':input')){
        event.preventDefault();
        $('#save').trigger('click');
    }
  });
});

CodePen: http://codepen.io/timbuethe/pen/AoKJj

3
Tim Büthe

Ignorer la touche Entrée uniquement dans les champs de saisie de texte ( source ): 

<script type="text/javascript"> 

  function stopRKey(evt) { 
     var evt = (evt) ? evt : ((event) ? event : null); 
     var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null); 
     if ((evt.keyCode == 13) && (node.type=="text"))  {return false;} 
  } 

  document.onkeypress = stopRKey; 

</script>
3
Sergey Chepurnov

Vous pouvez utiliser un h:commandLink pour le premier bouton et le styler avec css comme le h:commandButton.

Par exemple, bootstraps "btn btn-default" est identique sur commandLink et commandButton.

0
Stefan