24

Can you please tell me how to move focus on to the next field when the enter key is press? I use the dform plugin (which converts JSON to a form).

I Googled it, but this not working. Why doesn't my focus move on to the next field?

JSFiddle: http://jsfiddle.net/5WkVW/1/

$(document).keypress(function(e) {
        if(e.which == 13) {
    
                // Do something here if the popup is open
                alert("dd")
                var index = $('.ui-dform-text').index(this) + 1;
                $('.ui-dform-text').eq(index).focus();
            
        }
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<form id="testSuiteConfigurationform" name="testSuiteConfigurationform" method="post" class="ui-dform-form" novalidate="novalidate">
    <label class="ui-dform-label">
        <h3>Configuration Parameters</h3>
    </label>
    <div class="ui-dform-div inputDiv">
        <fieldset class="ui-dform-fieldset">
            <input type="text" id="totalRetryCount" name="totalRetryCount" tabindex="1" onblur="validateElement('Configuration', 'testSuiteConfigurationform','totalRetryCount')" class="ui-dform-text valid">
            <legend class="ui-dform-legend">Total Retry Count</legend>
            <label for="totalRetryCount" class="checked">✔</label>
        </fieldset>
        <fieldset class="ui-dform-fieldset">
            <input type="text" id="totalRepeatCount" name="totalRepeatCount" tabindex="2" onblur="validateElement('Configuration', 'testSuiteConfigurationform','totalRepeatCount')" class="ui-dform-text">
            <legend class="ui-dform-legend">Total Repeat Count</legend>
        </fieldset>
        <fieldset class="ui-dform-fieldset">
            <select id="summaryReportRequired" name="summaryReportRequired" tabindex="3" onblur="validateElement('Configuration', 'testSuiteConfigurationform','summaryReportRequired')" class="ui-dform-select">
                <option class="ui-dform-option" value="true">true</option>
                <option class="ui-dform-option" value="false">false</option>
            </select>
            <legend class="ui-dform-legend">Summary Report Required</legend>
        </fieldset>
        <fieldset class="ui-dform-fieldset">
            <select id="postConditionExecution" name="postConditionExecution" tabindex="4" onblur="validateElement('Configuration', 'testSuiteConfigurationform','postConditionExecution')" class="ui-dform-select">
                <option class="ui-dform-option" value="ALWAYS">ALWAYS</option>
                <option class="ui-dform-option" value="ON_SUCCESS">ON_SUCCESS</option>
            </select>
            <legend class="ui-dform-legend">Post Condition Execution</legend>
        </fieldset>
    </div>
</form>

*Note (from comments): It also needs to work on pages that do not have tabindex values set

Hitesh Tripathi
  • 856
  • 1
  • 11
  • 23
Shruti
  • 1,554
  • 8
  • 29
  • 66
  • I have tested my final version on all 4 HTML samples and it will work on pretty much any page. It uses a custom jQuery selector I added. Enjoy :) – iCollect.it Ltd Jun 13 '14 at 16:53

9 Answers9

44

It fails because this is the document in your code.

You want to use the index of the currently focused item (document.activeElement), or if you use delegated events you can make sure this is the current item.

This final version works whether there are tabindexes or not. It also wraps around:

JSFiddle 1: http://jsfiddle.net/TrueBlueAussie/5WkVW/11/

JSFiddle 2: http://jsfiddle.net/TrueBlueAussie/5WkVW/12/

They both use a custom jQuery selector that I add called :focusable to select all focusable element (including links):

// register jQuery extension
jQuery.extend(jQuery.expr[':'], {
    focusable: function (el, index, selector) {
        return $(el).is('a, button, :input, [tabindex]');
    }
});

$(document).on('keypress', 'input,select', function (e) {
    if (e.which == 13) {
        e.preventDefault();
        // Get all focusable elements on the page
        var $canfocus = $(':focusable');
        var index = $canfocus.index(this) + 1;
        if (index >= $canfocus.length) index = 0;
        $canfocus.eq(index).focus();
    }
});

You can use the same custom selector in the event handler if you like. Then it will even work on anchor links (if you change the event to keydown instead of keypress):

e.g.

$(document).on('keydown', ':focusable', function (e) {

Example with link: http://jsfiddle.net/5WkVW/15/

This also uses a delegated on, listening for the keydown event on the document. It then applies the jQuery selector, it then applies the function to any matching element that caused the event. This is much more efficient as it only applies the selector at event time (rather than apply multiple event handler to each DOM matching element).


Old versions below:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/5WkVW/3/

$(document).keypress(function(e) {
    if(e.which == 13) {

            // Do something here if the popup is open
            //alert("dd")
            var index = $('.ui-dform-text').index(document.activeElement) + 1;
            $('.ui-dform-text').eq(index).focus();

    }
});

*Note: alerts can interfere with focus, so use console.log for output like that and view in most browser's debug window (like Chrome's F12 debugging tools).

Update: http://jsfiddle.net/TrueBlueAussie/5WkVW/4/

This one wraps back to the first item from the last and also works on selects (the default behavior is blocked, so you can only use space to open or up/down to select options.

$('input,select').on('keypress', function (e) {
    if (e.which == 13) {
        e.preventDefault();
        var $next = $('[tabIndex=' + (+this.tabIndex + 1) + ']');
        console.log($next.length);
        if (!$next.length) {
            $next = $('[tabIndex=1]');
        }
        $next.focus();
    }
});

Requested "document" version: http://jsfiddle.net/TrueBlueAussie/5WkVW/5/

$(document).on('keypress', 'input,select', function (e) {
    if (e.which == 13) {
        e.preventDefault();
        var $next = $('[tabIndex=' + (+this.tabIndex + 1) + ']');
        console.log($next.length);
        if (!$next.length) {
            $next = $('[tabIndex=1]');
        }
        $next.focus();
    }
});
iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • 1
    Done... Works on both.. Should works on anything! :) – iCollect.it Ltd Jun 13 '14 at 16:49
  • @Gone Coding: I've accidentally hit the arrow and downvoted you, but I just noticed and can't change it now. Sorry about that. Apparently I can remove it if the post is edited, so if you want to make a trivial edit, I'll do that. – pyrocrasty Apr 10 '16 at 08:54
  • @Gone Coding: Thanks, I've changed it. – pyrocrasty Apr 11 '16 at 09:17
  • @GoneCoding this code does not work when next element is a disabled input element. is there any way i can add only 'not-disabled' elements in the ":focusable" list?? –  Feb 12 '17 at 08:20
  • i got the answer. i just replaced ':input' with ':enabled' and it worked! Thanks! –  Feb 12 '17 at 08:25
  • Great answer. Added condition to exclude currently invisible elements from canfocus list: return $(el).is('a, button, :enabled, [tabindex]') && $(el).is(':visible') ; – bgx Jun 19 '17 at 11:09
  • Is this possible with pure JS? – Ramon Bakker May 20 '18 at 19:05
  • @RamonBakker: Of course it is possible. jQuery is just JS under the hood. It just takes a lot more code. e.g. Listen for the `keypress` event on `document` and check the source to be an `input` or `select`. Then doa search for the next matching element. – iCollect.it Ltd May 21 '18 at 10:47
  • @GoneCoding i tried to create it in pure JS, https://codepen.io/ramonbakker1992/pen/VxRVqK, but its not working. It registers the enter key, but does'nt switch to next field. I think it has to do something with the query selector? – Ramon Bakker May 22 '18 at 12:54
  • @RamonBakker: Use say the Chrome debugger when you test your Fiddle. Error: `'[tabindex=2]' is not a valid selector` – iCollect.it Ltd May 22 '18 at 14:57
  • Okay, here is the working Pure Javascript solution: https://jsfiddle.net/mm0uctuv/2/ – Ramon Bakker May 22 '18 at 16:27
  • @RamonBakker: Very good. You should post it as an alternative answer in case someone does not want to use jQuery to solve this problem – iCollect.it Ltd May 25 '18 at 08:15
  • @GoneCoding Thx, i've added the answer. – Ramon Bakker May 28 '18 at 03:01
11

I've created a non-jQuery version. So only pure Javascript; https://jsfiddle.net/mm0uctuv/2/

Javascript:

var inputs = document.querySelectorAll("input,select");
for (var i = 0 ; i < inputs.length; i++) {
   inputs[i].addEventListener("keypress", function(e){
      if (e.which == 13) {
         e.preventDefault();
         var nextInput = document.querySelectorAll('[tabIndex="' + (this.tabIndex + 1) + '"]');
         if (nextInput.length === 0) {
            nextInput = document.querySelectorAll('[tabIndex="1"]');
         }
         nextInput[0].focus();
      }
   })
}

HTML:

<form>
   Field 1: <input type="text" tabindex="1"><br>
   Field 3: <input type="text" tabindex="3"><br>
   Field 2: <input type="text" tabindex="2">
</form>
Ramon Bakker
  • 1,075
  • 11
  • 24
  • 1
    Avoid using tabindex values greater than 0. Doing so makes it difficult for people who rely on assistive technology to navigate and operate page content. [From MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) – mtbno Oct 08 '21 at 23:09
4

On the top-level div, add onKeyDown={this.onKeyDown.bind(this)} and add the following method (ES6) to the same class as the div:

onKeyDown(event) {
    if (event.keyCode === 13) {
        event.preventDefault()
        const inputs =
            Array.prototype.slice.call(document.querySelectorAll("input"))
        const index =
            (inputs.indexOf(document.activeElement) + 1) % inputs.length
        const input = inputs[index]
        input.focus()
        input.select()
    }
}
Ralph
  • 31,584
  • 38
  • 145
  • 282
2

The following code should do it; it uses the tabIndex property. Let us know if that's is not acceptable:

$(function() {
    $('input').on('keypress', function(e) {
        e.which !== 13 || $('[tabIndex=' + (+this.tabIndex + 1) + ']')[0].focus();
    });
});

The drop down already has enter key slated for opening the drop down.

JS FIDDLE DEMO

To be able to do something before moving to the next form element, you can use the following version:

$(function() {
    $(document).on('keypress', function(e) {
        var that = document.activeElement;
        if( e.which == 13 ) {
            e.preventDefault();
            alert( "dd" );
            $('[tabIndex=' + (+that.tabIndex + 1) + ']')[0].focus();
        }            
    });
});

DEMO

PeterKA
  • 24,158
  • 5
  • 26
  • 48
0

Try the following JavaScript code that I modified from your fiddle. The default behavior of the select elements will be to expand on the keypress. The plus sign at the beginning of +$(this).attr("tabindex")

Converts the text attribute value to int.

$(".ui-dform-text").keypress(function(e) {
    if(e.which == 13) {

        // Do something here if the popup is open
        alert($(this).attr("tabindex"));
        var index = +$(this).attr("tabindex") + 1;


        $("[tabindex='" + index +"']").focus();
    }
});
Pang
  • 9,564
  • 146
  • 81
  • 122
JDTLH9
  • 1,765
  • 1
  • 23
  • 34
0

This is mostly a joke but here is a Vanilla JS version using the newest APIs as long as you have a modern browser, it should be bullet proof

Here's what's happening:

  1. Select Elements, inputs, etc... (excluding disabled, hidden, etc...)
  2. Using the spread syntax, convert array (NodeList) to an object (here it's NodeObject)
  3. Loop through the Objects aka Elements aka Nodes
  4. Each iteration will pass the current element (Node) and the next element (NextNode) to an arrow function.
  5. Continue if NextNode is an element
  6. Then add a keypress event to the current element
  7. Inside the event:
    • Continue only if the enter key was pressed (using e.key NOT e.keyCode or e.which -- which are deprecated)
    • Stop the Form from being submitted
    • Focus the next element
    • If we can, Select the text in the next node

And just like that you have some really unreadable code that is mostly parenthesis and arrow functions :)

// NodeList of applicable inputs, select, button
let NodesArray = document.querySelectorAll(`
                  #form input:not([disabled])[type]:not([type=\"hidden\"]),
                  #form select:not([disabled]),
                  #form button:not([disabled])[type=\"submit\"]
                `);

// Spread the array to an object so we can load the next node without 
// keeping track of indexes (barf)
(NodesObject => {

  // Node and NextNode are Elements.
  // You can update and get data if you want
  Object.keys(NodesObject).forEach(i => (({ Node, NextNode }) => {

    // Break if we dont have a NextNode
    if (NextNode === false) return;


    Node.addEventListener('keypress', KeyboardEvent => {

      // Only continue if event.key was "Enter"
      if (KeyboardEvent.key !== "Enter") return;

      // Dont submit, thx
      KeyboardEvent.preventDefault();

      // Do the thing
      NextNode.focus();

      // Not all elements have a select method
      if (typeof NextNode.select === 'function') NextNode.select();
    });


  })({
    Node:     NodesObject[i],
    NextNode: NodesObject[(parseInt(i) + 1)] ?? false
  }));

})({ ...NodesArray });
CodeJunkie
  • 339
  • 3
  • 16
0

it looks the same, but I offer something simple, maybe helpful, and easy to remember, and this is what I use

html

<input placeholder="nama">
<input placeholder="email">
<input placeholder="password">
<button>MASUK<button>

js

$('INPUT').keydown( e => e.which === 13?$(e.target).next().focus():"");
malik kurosaki
  • 1,747
  • 15
  • 9
0
// This will work; add this code in your on ready function and define your parent element which includes child elements to be focused.

const mainDiv = document.getElementById(`auto-focuser`); //here your parent element you need to focus
const keyDownEvent = (event) => {
    if (event.key === "Enter") {
        if (event.target.tagName === "TEXTAREA" && (event.target.innerHTML !== "" && event.target.innerHTML.substr(-1) !== "\n"))
            return;
        if (event.target.attributes.tabindex) {
            const nextElm = mainDiv.querySelectorAll(`[tabindex='${parseInt(event.target.attributes.tabindex.value) + 1}']`).item(0)
            if (nextElm) {
                nextElm.focus()
                if (nextElm.tagName === "INPUT" || nextElm.tagName === "TEXTAREA") {
                    nextElm.select()
                    nextElm.selectionStart = nextElm.selectionEnd = nextElm.value.length;
                }
                event.preventDefault()
            }
        }
    }
}
mainDiv?.addEventListener('keydown', keyDownEvent);

Vaitul Bhayani
  • 654
  • 6
  • 5
0

1.first = you should put 'textbox' on your class name in input

2.second = put specific id for each input

then write this code for select that element and go to next element.

I select each element by each id and put next() function on keypress of every input.

function next(event,elem){
if ( event.keyCode == 13)
{
    var list = document.getElementsByClassName("textbox");
    for (var i=0 ; i<list.length ; i++)
    {
        if (elem.id == list[i].id)
        {
            var index = i + 1;
            list[index].focus();
        }
    }
  }

}

event args use for keybord press// elem args use for element that we press eneter