Je cherche à créer un formulaire où appuyer sur la touche Entrée fait passer le focus à l'élément de formulaire "suivant" de la page. La solution que je n'arrête pas de trouver sur le Web est ...
<body onkeydown="if(event.keyCode==13){event.keyCode=9; return event.keyCode}">
Malheureusement, cela ne semble fonctionner que dans IE. Le vrai problème de cette question est donc de savoir si quelqu'un connaît une solution qui fonctionne pour FF et Chrome? De plus, je préférerais ne pas avoir à ajouter les événements onkeydown aux éléments de formulaire eux-mêmes, mais si c'est le seul moyen, il faudra le faire.
Cette question est similaire à question 905222 , mais mérite à elle seule sa propre question.
Edit: aussi, j'ai vu des gens dire que ce n'est pas un bon style, car il diffère du comportement des formulaires auquel les utilisateurs sont habitués. Je suis d'accord! C'est une demande du client :(
J'ai utilisé la logique suggérée par Andrew qui est très efficace. Et voici ma version:
$('body').on('keydown', 'input, select, textarea', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
J'ai réécrit la réponse de Andre Van Zuydam , qui n'a pas fonctionné pour moi, dans jQuery. Cette caputures à la fois Enter et Shift+Enter. Enter onglets en avant, et Shift+Enter onglets en arrière.
J'ai également réécrit la manière dont self
est initialisé par l'élément actuellement sélectionné. Le formulaire est également sélectionné de cette façon. Voici le code:
// Map [Enter] key to work like the [Tab] key
// Daniel P. Clark 2014
// Catch the keydown for the entire document
$(document).keydown(function(e) {
// Set self as the current item in focus
var self = $(':focus'),
// Set the form by the current item in focus
form = self.parents('form:eq(0)'),
focusable;
// Array of Indexable/Tab-able items
focusable = form.find('input,a,select,button,textarea,div[contenteditable=true]').filter(':visible');
function enterKey(){
if (e.which === 13 && !self.is('textarea,div[contenteditable=true]')) { // [Enter] key
// If not a regular hyperlink/button/textarea
if ($.inArray(self, focusable) && (!self.is('a,button'))){
// Then prevent the default [Enter] key behaviour from submitting the form
e.preventDefault();
} // Otherwise follow the link/button as by design, or put new line in textarea
// Focus on the next item (either previous or next depending on shift)
focusable.eq(focusable.index(self) + (e.shiftKey ? -1 : 1)).focus();
return false;
}
}
// We need to capture the [Shift] key and check the [Enter] key either way.
if (e.shiftKey) { enterKey() } else { enterKey() }
});
textarea
est inclus parce que nous " faisons " voulons y entrer. En outre, une fois dedans, nous ne voulons pas arrêter le comportement par défaut de Enter de mettre dans une nouvelle ligne.
a
et button
autoriser l'action par défaut, " et " reste concentré sur l'élément suivant, car ils ne chargent pas toujours une autre page. Il peut y avoir un déclencheur/effet sur ceux-ci tels qu'un accordéon ou un contenu à onglets. Ainsi, une fois que vous avez déclenché le comportement par défaut et que la page produit ses effets spéciaux, vous souhaitez toujours passer à l'élément suivant, car votre déclencheur l'a peut-être bien introduit.
Cela a fonctionné pour moi
$(document).on('keydown', ':tabbable', function (e) {
if (e.which == 13 || e.keyCode == 13 )
{ e.preventDefault();
var $canfocus = $(':tabbable:visible')
var index = $canfocus.index(document.activeElement) + 1;
if (index >= $canfocus.length) index = 0;
$canfocus.eq(index).focus();
}
});
Merci pour le bon script.
Je viens d'ajouter l'événement shift sur la fonction ci-dessus pour revenir entre les éléments, j'ai pensé que quelqu'un pourrait en avoir besoin.
$('body').on('keydown', 'input, select, textarea', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
, prev
;
if (e.shiftKey) {
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
prev = focusable.eq(focusable.index(this)-1);
if (prev.length) {
prev.focus();
} else {
form.submit();
}
}
}
else
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
Il y a des problèmes avec toutes les implémentations données ici. Certains ne fonctionnent pas correctement avec textareas et les boutons submit, la plupart ne vous permettent pas d'utiliser shift pour revenir en arrière, aucun d'entre eux n'utilise de tabindex si vous en avez, et aucun d'entre eux ne passe du dernier au premier Jusqu'au dernier.
Pour que la touche [entrée] agisse comme la touche [tab] tout en fonctionnant correctement avec les zones de texte et les boutons d'envoi, utilisez le code suivant. De plus, ce code vous permet d’utiliser la touche Maj pour revenir en arrière et les onglets se superposent d’avant en arrière.
Code source: https://github.com/mikbe/SaneEnterKey
mbsd_sane_enter_key = ->
input_types = "input, select, button, textarea"
$("body").on "keydown", input_types, (e) ->
enter_key = 13
tab_key = 9
if e.keyCode in [tab_key, enter_key]
self = $(this)
# some controls should just press enter when pressing enter
if e.keyCode == enter_key and (self.prop('type') in ["submit", "textarea"])
return true
form = self.parents('form:eq(0)')
# Sort by tab indexes if they exist
tab_index = parseInt(self.attr('tabindex'))
if tab_index
input_array = form.find("[tabindex]").filter(':visible').sort((a,b) ->
parseInt($(a).attr('tabindex')) - parseInt($(b).attr('tabindex'))
)
else
input_array = form.find(input_types).filter(':visible')
# reverse the direction if using shift
move_direction = if e.shiftKey then -1 else 1
new_index = input_array.index(this) + move_direction
# wrap around the controls
if new_index == input_array.length
new_index = 0
else if new_index == -1
new_index = input_array.length - 1
move_to = input_array.eq(new_index)
move_to.focus()
move_to.select()
false
$(window).on 'ready page:load', ->
mbsd_sane_enter_key()
var mbsd_sane_enter_key = function() {
var input_types;
input_types = "input, select, button, textarea";
return $("body").on("keydown", input_types, function(e) {
var enter_key, form, input_array, move_direction, move_to, new_index, self, tab_index, tab_key;
enter_key = 13;
tab_key = 9;
if (e.keyCode === tab_key || e.keyCode === enter_key) {
self = $(this);
// some controls should react as designed when pressing enter
if (e.keyCode === enter_key && (self.prop('type') === "submit" || self.prop('type') === "textarea")) {
return true;
}
form = self.parents('form:eq(0)');
// Sort by tab indexes if they exist
tab_index = parseInt(self.attr('tabindex'));
if (tab_index) {
input_array = form.find("[tabindex]").filter(':visible').sort(function(a, b) {
return parseInt($(a).attr('tabindex')) - parseInt($(b).attr('tabindex'));
});
} else {
input_array = form.find(input_types).filter(':visible');
}
// reverse the direction if using shift
move_direction = e.shiftKey ? -1 : 1;
new_index = input_array.index(this) + move_direction;
// wrap around the controls
if (new_index === input_array.length) {
new_index = 0;
} else if (new_index === -1) {
new_index = input_array.length - 1;
}
move_to = input_array.eq(new_index);
move_to.focus();
move_to.select();
return false;
}
});
};
$(window).on('ready page:load', function() {
mbsd_sane_enter_key();
}
Le plus simple extrait de Vanilla JS que j'ai créé:
document.addEventListener('keydown', function (event) {
if (event.keyCode === 13 && event.target.nodeName === 'INPUT') {
var form = event.target.form;
var index = Array.prototype.indexOf.call(form, event.target);
form.elements[index + 1].focus();
event.preventDefault();
}
});
Fonctionne dans IE 9+ et les navigateurs modernes.
La modification de ce comportement crée en réalité une expérience utilisateur bien meilleure que le comportement par défaut implémenté de manière native. Considérez que le comportement de la touche Entrée est déjà incohérent du point de vue de l'utilisateur, car dans une entrée à une seule ligne, entrée tend à soumettre un formulaire, tandis que dans une zone de texte à plusieurs lignes, elle ajoute simplement une nouvelle ligne au contenu de l'élément. champ.
Je l'ai récemment fait comme ça (utilise jQuery):
$('input.enterastab, select.enterastab, textarea.enterastab').live('keydown', function(e) {
if (e.keyCode==13) {
var focusable = $('input,a,select,button,textarea').filter(':visible');
focusable.eq(focusable.index(this)+1).focus();
return false;
}
});
Ce n'est pas très efficace, mais fonctionne assez bien et est fiable - ajoutez simplement la classe 'enterastab' à tout élément d'entrée qui devrait se comporter de cette manière.
J'ai retravaillé la solution OP en une reliure Knockout et j'ai pensé la partager. Merci beaucoup :-)
Voici a Fiddle
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js" type="text/javascript"></script>
</head>
<body>
<div data-bind="nextFieldOnEnter:true">
<input type="text" />
<input type="text" />
<select>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<input type="text" />
<input type="text" />
</div>
<script type="text/javascript">
ko.bindingHandlers.nextFieldOnEnter = {
init: function(element, valueAccessor, allBindingsAccessor) {
$(element).on('keydown', 'input, select', function (e) {
var self = $(this)
, form = $(element)
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
var nextIndex = focusable.index(this) == focusable.length -1 ? 0 : focusable.index(this) + 1;
next = focusable.eq(nextIndex);
next.focus();
return false;
}
});
}
};
ko.applyBindings({});
</script>
</body>
</html>
Voici une directive angular.js pour faire en sorte que vous passiez au champ suivant en vous inspirant des autres réponses. Il y a peut-être un code bizarre ici, car je n'utilise que le jQlite fourni avec angular. Je crois que la plupart des fonctionnalités ici fonctionnent dans tous les navigateurs> IE8.
angular.module('myapp', [])
.directive('pdkNextInputOnEnter', function() {
var includeTags = ['INPUT', 'SELECT'];
function link(scope, element, attrs) {
element.on('keydown', function (e) {
// Go to next form element on enter and only for included tags
if (e.keyCode == 13 && includeTags.indexOf(e.target.tagName) != -1) {
// Find all form elements that can receive focus
var focusable = element[0].querySelectorAll('input,select,button,textarea');
// Get the index of the currently focused element
var currentIndex = Array.prototype.indexOf.call(focusable, e.target)
// Find the next items in the list
var nextIndex = currentIndex == focusable.length - 1 ? 0 : currentIndex + 1;
// Focus the next element
if(nextIndex >= 0 && nextIndex < focusable.length)
focusable[nextIndex].focus();
return false;
}
});
}
return {
restrict: 'A',
link: link
};
});
Voici comment je l'utilise dans l'application sur laquelle je travaille, en ajoutant simplement la directive pdk-next-input-on-enter
sur un élément. J'utilise un scanner de codes à barres pour entrer des données dans des champs. La fonction par défaut du scanner est d'émuler un keayboard, en injectant une clé d'entrée après avoir saisi les données du code à barres numérisé.
Ce code a un effet secondaire (positif pour mon cas d'utilisation): s'il déplace le focus sur un bouton, l'événement enter keyup activera l'action du bouton. Cela a très bien fonctionné pour mon flux car le dernier élément de formulaire de mon balisage est un bouton que je veux activer une fois que tous les champs ont été "tabulés" en scannant les codes à barres.
<!DOCTYPE html>
<html ng-app=myapp>
<head>
<script src="angular.min.js"></script>
<script src="controller.js"></script>
</head>
<body ng-controller="LabelPrintingController">
<div class='.container' pdk-next-input-on-enter>
<select ng-options="p for p in partNumbers" ng-model="selectedPart" ng-change="selectedPartChanged()"></select>
<h2>{{labelDocument.SerialNumber}}</h2>
<div ng-show="labelDocument.ComponentSerials">
<b>Component Serials</b>
<ul>
<li ng-repeat="serial in labelDocument.ComponentSerials">
{{serial.name}}<br/>
<input type="text" ng-model="serial.value" />
</li>
</ul>
</div>
<button ng-click="printLabel()">Print</button>
</div>
</body>
</html>
J'ai eu un problème similaire, où je voulais appuyer sur + sur le pavé numérique pour passer au champ suivant. Maintenant, j'ai publié une bibliothèque qui, je pense, vous aidera.
PlusAsTab : Un plugin jQuery pour utiliser le pavé numérique plus comme une touche de tabulation équivalente.
Puisque tu veux enter/↵ à la place, vous pouvez définir les options. Découvrez quelle clé vous souhaitez utiliser avec le démo jQuery event.which .
JoelPurra.PlusAsTab.setOptions({
// Use enter instead of plus
// Number 13 found through demo at
// https://api.jquery.com/event.which/
key: 13
});
// Matches all inputs with name "a[]" (needs some character escaping)
$('input[name=a\\[\\]]').plusAsTab();
Vous pouvez l'essayer vous-même dans le PlusAsTab entre en démo .
Si vous le pouviez, je reconsidérerais ceci: l'action par défaut consistant à appuyer sur <Enter>
dans un formulaire soumet le formulaire et tout ce que vous faites pour modifier cette action/comportement attendu peut entraîner des problèmes d'utilisation sur le site.
Vanilla js avec prise en charge des touches Maj + Entrée et possibilité de choisir les balises HTML à mettre au point Devrait fonctionner IE9 +.
onKeyUp(e) {
switch (e.keyCode) {
case 13: //Enter
var focusableElements = document.querySelectorAll('input, button')
var index = Array.prototype.indexOf.call(focusableElements, document.activeElement)
if(e.shiftKey)
focus(focusableElements, index - 1)
else
focus(focusableElements, index + 1)
e.preventDefault()
break;
}
function focus(elements, index) {
if(elements[index])
elements[index].focus()
}
}
Voici ce que je suis venu avec.
form.addEventListener("submit", (e) => { //On Submit
let key = e.charCode || e.keyCode || 0 //get the key code
if (key = 13) { //If enter key
e.preventDefault()
const inputs = Array.from(document.querySelectorAll("form input")) //Get array of inputs
let nextInput = inputs[inputs.indexOf(document.activeElement) + 1] //get index of input after the current input
nextInput.focus() //focus new input
}
}
Essaye ça...
$(document).ready(function () {
$.fn.enterkeytab = function () {
$(this).on('keydown', 'input,select,text,button', function (e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
//if disable try get next 10 fields
if (next.is(":disabled")){
for(i=2;i<10;i++){
next = focusable.eq(focusable.index(this) + i);
if (!next.is(":disabled"))
break;
}
}
next.focus();
}
return false;
}
});
}
$("form").enterkeytab();
});
Je l'ai travailler uniquement en JavaScript. Firefox ne vous laissera pas mettre à jour le code de code source, vous ne pouvez donc que capturer le code de base 13 et le forcer à se concentrer sur l'élément suivant par tabIndex comme si le code clé 9 avait été activé. La partie la plus délicate consiste à trouver le prochain tabIndex. J'ai testé cela uniquement sur IE8-IE10 et Firefox et cela fonctionne:
function ModifyEnterKeyPressAsTab(event)
{
var caller;
var key;
if (window.event)
{
caller = window.event.srcElement; //Get the event caller in IE.
key = window.event.keyCode; //Get the keycode in IE.
}
else
{
caller = event.target; //Get the event caller in Firefox.
key = event.which; //Get the keycode in Firefox.
}
if (key == 13) //Enter key was pressed.
{
cTab = caller.tabIndex; //caller tabIndex.
maxTab = 0; //highest tabIndex (start at 0 to change)
minTab = cTab; //lowest tabIndex (this may change, but start at caller)
allById = document.getElementsByTagName("input"); //Get input elements.
allByIndex = []; //Storage for elements by index.
c = 0; //index of the caller in allByIndex (start at 0 to change)
i = 0; //generic indexer for allByIndex;
for (id in allById) //Loop through all the input elements by id.
{
allByIndex[i] = allById[id]; //Set allByIndex.
tab = allByIndex[i].tabIndex;
if (caller == allByIndex[i])
c = i; //Get the index of the caller.
if (tab > maxTab)
maxTab = tab; //Get the highest tabIndex on the page.
if (tab < minTab && tab >= 0)
minTab = tab; //Get the lowest positive tabIndex on the page.
i++;
}
//Loop through tab indexes from caller to highest.
for (tab = cTab; tab <= maxTab; tab++)
{
//Look for this tabIndex from the caller to the end of page.
for (i = c + 1; i < allByIndex.length; i++)
{
if (allByIndex[i].tabIndex == tab)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
//Look for the next tabIndex from the start of page to the caller.
for (i = 0; i < c; i++)
{
if (allByIndex[i].tabIndex == tab + 1)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
//Continue searching from the caller for the next tabIndex.
}
//The caller was the last element with the highest tabIndex,
//so find the first element with the lowest tabIndex.
for (i = 0; i < allByIndex.length; i++)
{
if (allByIndex[i].tabIndex == minTab)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
}
}
Pour utiliser ce code, ajoutez-le à votre balise HTML:
<input id="SomeID" onkeydown="ModifyEnterKeyPressAsTab(event);" ... >
Ou ajoutez-le à un élément en javascript:
document.getElementById("SomeID").onKeyDown = ModifyEnterKeyPressAsTab;
Quelques autres notes:
Je n'avais besoin que de travailler sur mes éléments d'entrée, mais vous pouvez l'étendre à d'autres éléments de document si nécessaire. Pour cela, getElementsByClassName est très utile, mais c'est un tout autre sujet.
Une limitation est qu'il ne fait que des tabulations entre les éléments que vous avez ajoutés à votre tableau allById. Cela n'indique pas que votre navigateur peut contenir d'autres éléments, tels que des barres d'outils et des menus en dehors de votre document html. C'est peut-être une fonctionnalité au lieu d'une limitation. Si vous le souhaitez, interceptez keyCode 9 et ce comportement fonctionnera également avec la touche de tabulation.
Beaucoup de réponses ici utilisent e.keyCode
et e.which
qui sont obsolètes.
Au lieu de cela, vous devriez utiliser e.key === 'Enter'
.
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
Avec HTML:
<body onkeypress="if(event.key==='Enter' && event.target.form){focusNextElement(event); return false;}">
Avec jQuery:
$(window).on('keypress', function (ev)
{
if (ev.key === "Enter" && ev.currentTarget.form) focusNextElement(ev)
}
Avec Vanilla JS:
document.addEventListener ('keypress', function (ev) {if (ev.key === "Entrée" && ev.currentTarget.form) focusNextElement (ev);});
Vous pouvez prendre la fonction focusNextElement()
à partir d’ici: https://stackoverflow.com/a/35173443/3356679
Vous pouvez utiliser mon code ci-dessous, testé dans Mozilla, IE et Chrome
// Use to act like tab using enter key
$.fn.enterkeytab=function(){
$(this).on('keydown', 'input, select,', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
alert("wd");
//form.submit();
}
return false;
}
});
}
Comment utiliser?
$ ("# forme"). enterkeytab (); // entrer l'onglet clé