web-dev-qa-db-fra.com

Meilleure façon de trouver le prochain élément de saisie de formulaire dans jQuery?

Avec jQuery, quel est le meilleur moyen de trouver le prochain élément de formulaire sur la page, à partir d’un élément quelconque? Quand je dis élément de formulaire, je veux dire <input>, <select>, <button> ou <textarea>.

Dans les exemples suivants, l'élément avec l'id "this" est le point de départ arbitraire et l'élément avec l'id "next" est celui que je veux trouver. La même réponse devrait fonctionner pour tous les exemples.

Exemple 1:

<ul>
 <li><input type="text" /></li>
 <li><input id="this" type="text" /></li>
</ul>

<ul>
 <li><input id="next" type="text" /></li>
</ul>

<button></button>

Exemple 2:

<ul>
 <li><input id="this" type="text" /></li>
</ul>

<button id="next"></button>

Exemple 3:

<input id="this" type="text" />
<input id="next" type="text" />

Exemple 4:

<div>
  <input id="this" type="text" />
  <input type="hidden" />
  <div>
    <table>
      <tr><td></td><td><input id="next" type="text" /></td></tr>
    </table>
  </div>
  <button></button>
</div>

ÉDITER: les deux réponses fournies à ce jour nécessitent l’écriture d’un numéro de séquence sur tous les éléments en entrée de la page. Comme je l’ai mentionné dans les commentaires de l’un d’eux, c’est un peu ce que je fais déjà et je préférerais de beaucoup avoir une solution en lecture seule, car cela se fera dans un plugin.

37
kodos

gloire,

Qu'en est-il d'utiliser .index?

par exemple $(':input:eq(' + ($(':input').index(this) + 1) + ')');

51
redsquare

redsquare a tout à fait raison et constitue une excellente solution que j'ai également utilisée dans l'un de mes projets.

Je voulais simplement souligner qu'il manque quelques parenthèses, car la solution actuelle concatène l'index avec 1 au lieu de les additionner.

Donc, la solution corrigée ressemblerait à ceci:

$(":input:eq(" + ($(":input").index(this) + 1) + ")");

Désolé pour le double post, mais je n'ai pas trouvé de moyen de commenter son post ...

13
reSPAWNed

Cette solution ne nécessite pas d'index et fonctionne également bien avec tabindex. En d'autres termes, elle vous donne l'élément exact que le navigateur vous donnerait sous l'onglet, à chaque fois, sans aucun travail supplémentaire.

function nextOnTabIndex(element) {
      var fields = $($('form')
                    .find('a[href], button, input, select, textarea')
                    .filter(':visible').filter('a, :enabled')
                    .toArray()
                    .sort(function(a, b) {
                      return ((a.tabIndex > 0) ? a.tabIndex : 1000) - ((b.tabIndex > 0) ? b.tabIndex : 1000);
                    }));


      return fields.eq((fields.index(element) + 1) % fields.length);
    }

Cela fonctionne en récupérant tous les champs tabbables du formulaire (comme autorisé par http://www.w3.org/TR/html5/editing.html#focus-management ), puis en triant les champs en fonction de ( http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute ) pour définir le prochain élément à utiliser. Une fois qu'il a cela, il regarde où se trouve le champ passé dans ce tableau et retourne l'élément suivant.

Quelques points à noter:

  • jQuery semble prendre en charge sort () sur un objet jQuery, mais je ne trouve pasit de manière explicite dans la documentation, appelant donc toArray () puis réemballant le tableau dans un objet jQuery. 
  • Il y a d'autres champs quiit est acceptable, mais je les ai laissés de côté car ils ne sont pas des champs de formulaire standard

Le code que j'ai utilisé pour tester cela était (avec jQuery 1.7):

<script>
  $(function() {
    $('a[href], button, input, select, textarea').click(function() {
      console.log(nextOnTabIndex($(this)).attr('name'));
    })
  });
</script>

<form>
  <input type='text' name='a'/>
  <input type='text' name='b' tabindex='1' />
  <a>Hello</a>
  <input type='text' name='c'/>
  <textarea name='d' tabindex='2'></textarea>
  <input id='submit' type='submit' name='e' tabindex='1' />
</form>
10
Jai

Après avoir essayé tous les codes que j'ai pu trouver (et eu des problèmes entre les navigateurs), j'ai trouvé celui qui fonctionne dans les principaux navigateurs. Impossible d'utiliser les routines précédentes à cause de problèmes étranges.

$(document.body).keydown(function(event) {
    if(event.keyCode == 13 ) {
        $(":input")[$(":input").index(document.activeElement) + 1].focus();
        return false;
    }
});

J'espère que ceci aide quelqu'un d'autre. Prendre plaisir.

7
Jeff Mathews

Vous pouvez attribuer à chaque élément de formulaire un identifiant (ou un nom de classe unique) l'identifiant en tant qu'élément de formulaire et lui attribuant également un index. Par exemple:

<div>
    <input id="FormElement_0" type="text" />
    <input id="FormElement_1" type="text" />
<div>

Ensuite, si vous voulez parcourir le premier élément à la seconde, vous pouvez faire quelque chose comme ceci:

//I'm assuming "this" is referring to the first input

//grab the id
var id = $(this).attr('id');

//get the index from the id and increment it
var index = parseInt(id.split('_')[0], 10);
index++;

//grab the element witht that index
var next = $('#FormElement_' + index);

L'avantage de ceci est que vous pouvez marquer n'importe quel élément à côté, peu importe l'emplacement ou le type. Vous pouvez également contrôler l'ordre de votre traversée. Ainsi, si pour une raison quelconque vous souhaitez ignorer un élément et y revenir plus tard, vous pouvez également le faire.

2
jckeyes

Vous pouvez le faire pour obtenir une liste complète des éléments de formulaire que vous recherchez:

var yourFormFields = $("yourForm").find('button,input,textarea,select');

Ensuite, il devrait être facile de trouver l'élément suivant:

var index = yourFormFields.index( this ); // the index of your current element in the list. if the current element is not in the list, index = -1

if ( index > -1 && ( index + 1 ) < yourFormFields.length ) { 

                    var nextElement = yourFormFields.eq( index + 1 );

                    }
2
alexmeia

Ou vous pouvez utiliser l'attribut html 'tabindex' qui est utilisé lorsqu'un utilisateur utilise un onglet autour d'un formulaire pour passer à tabindex = "i" à tabindex = "i + 1". Vous pouvez utiliser jQuery pour obtenir l'attribut très facilement. Permettrait un retour agréable aux utilisateurs sans javascript activé, également.

1
Chris Serra

Je suis arrivé avec une fonction qui fait le travail sans définir explicitement les index:

function nextInput(form, id) {
    var aInputs = $('#' + form).find(':input[type!=hidden]');
    for (var i in aInputs) {
        if ($(aInputs[i]).attr('id') == id) {
            if (typeof(aInputs[parseInt(i) + 1]) != 'undefined') {
                return aInputs[parseInt(i) + 1];
            }
        }
    }
}

Et voici un exemple de travail. Les balises de formulaire sont pour la cohérence. Tout ce dont vous avez besoin est un parent commun et vous pouvez même simplement utiliser la balise body comme parent (avec une légère modification de la fonction).

Collez ceci dans un fichier et ouvrez-le avec firefox/firebug et vous verrez qu'il renvoie l'élément correct pour tous vos exemples:

<html>
  <head>
    <script src="http://www.google.com/jsapi"></script>
    <script>
      function nextInput(form, id) {
        var aInputs = $('#' + form).find(':input[type!=hidden]');
        for (var i in aInputs) {
          if ($(aInputs[i]).attr('id') == id) {
            if (typeof(aInputs[parseInt(i) + 1]) != 'undefined') {
              return aInputs[parseInt(i) + 1];
            }
          }
        }
      }

      google.load("jquery", "1.2.6");
      google.setOnLoadCallback(function() {
        console.log(nextInput('myform1', 'this1'));
        console.log(nextInput('myform2', 'this2'));
        console.log(nextInput('myform3', 'this3'));
        console.log(nextInput('myform4', 'this4'));
      });
    </script>
  </head>
  <body>
    <form id="myform1">
      <ul>
         <li><input type="text" /></li>
         <li><input id="this1" type="text" /></li>
      </ul>
      <ul>
        <li><input id="next1" type="text" /></li>
      </ul>
    </form>

    <form id="myform2">
      <ul>
         <li><input type="text" /></li>
         <li><input id="this2" type="text" /></li>
      </ul>
      <ul>
        <li><input id="next2" type="text" /></li>
      </ul>
    </form>

    <form id="myform3">
      <input id="this3" type="text" />
      <input id="next3" type="text" />
    </form>

    <form id="myform4">
      <div>
        <input id="this4" type="text" />
        <input type="hidden" />
        <div>
        <table>
          <tr><td></td><td><input id="next4" type="text" /></td></tr>
        </table>
        </div>
        <button></button>
      </div>
    </form>
  </body>
</html>
1
enobrev
var elementSelector = "input:visible,textarea:visible";
var nextSibling = $(elementSelector )[$(elementSelector ).index() + 1];
//$(nextSibling).focus(); possible action

Je pense juste que la solution ci-dessus est plus simple, ou vous pouvez simplement l'ajouter en une seule ligne si vous le souhaitez

var nextSibling = $("input:visible,textarea:visible")[$("input:visible,textarea:visible").index() + 1];
0
NicoJuicy

Toutes les solutions utilisant index (ou nextAll) ne fonctionneront que si toutes les entrées de formulaire sont frères, par exemple. dans le même bloc <div>. On résout ce problème en créant un tableau d'identifiants de toutes les entrées visibles de la page, non lisibles, et en sélectionnant le premier après le contrôle actuel, en arrondissant si le contrôle actuel est le dernier de la page.

ids = $(":input:visible:not([readonly])").map(function () { return this.id });
nextId = ids[($.inArray($(this).attr("id"), ids) + 1) % ids.length];
$("#" + nextId).focus();

L'utilisation de la fonction map la rend un peu plus succincte que les solutions impliquant des itérateurs. 

0
PiersB

Vous pouvez utiliser le plugin de champ jQuery qui vous permet de le faire.

0
Anton Kuzmin

Cela a bien fonctionné pour moi et saute correctement les entrées cachées:

input_el.nextAll( 'input:visible:first' ).focus();
0
Jay Haase