Lakmal Premaratne
Lakmal Premaratne

Reputation: 1229

Set focus to the next input element

I have a bootstrap form where I want to set the focus to the next 'enabled' input element upon pressing enter key. When I press enter in Barcode input element, I want to set the focus to the Quantity input element since it is the next enabled input element.

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

    <div class="row">
     <div class="col-3 pr-0">
      <div class="form-group">
       <label for="txtBarcode">Barcode</label>
       <input type="text" id="txtBarcode" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
     <div class="col-7 pl-2 pr-0">
      <div class="form-group">
       <label for="txtPartDesc">Description</label>
       <input type="text" id="txtPartDesc" name="part_desc" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
     <div class="col-2 pl-2">
      <div class="form-group">
       <label for="txtUom">UoM</label>
       <input type="text" id="txtUom" name="barcode" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
    </div>
    <div class="row">
     <div class="col-4 pr-0">
      <div class="form-group">
       <label for="txtQuantity">Quantity</label>
       <input type="text" id="txtQuantity" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
    </div>

What I have tried so far is:

$(":input").keydown(function(event){
    if (event.keyCode === 13) {
        $(this).nextAll(':input:enabled').first().focus();
    }
});

But this doesn't work as I expect.

Upvotes: 2

Views: 2375

Answers (3)

Dacre Denny
Dacre Denny

Reputation: 30400

If I understand your question correctly then one solution to this problem is to update your keydown() handler like so:

  if (event.keyCode === 13) {

      // Get all enabled inputs in the document
      var inputs = $('input:enabled');

      // Iterate all inputs, searching for the index of the "next" input to "this"
      for(var i = 0; i < inputs.length; i++) {

        // If the "global" index of "this" input is found
        if( $(inputs).eq(i).is( $(this) ) ) {

          // Then select the "next" input by incrementing the index, and call
          // focus on that input if it exists
          inputs.eq(i + 1)
          .css({ border : '1px solid red' }) // Added to help visualise focus, remove this line 
          .focus();

          // Exit the loop now that focus has been called on "next" input
          break
        }
      } 
    }

The idea here is to select the next input element based on the order that they occur in the DOM, rather than to select the next input element based on adjacent siblings to the input that "enter" is pressed. This solution also corrects a few minor errors in your code's selector syntax. Here's a working demo:

$("input").keydown(function(event){
 
    if (event.keyCode === 13) {
     
      var inputs = $('input:enabled');
      
      for(var i = 0; i < inputs.length; i++) {
        if( $(inputs).eq(i).is( $(this) ) ) {
          inputs.eq(i + 1)
          .css({ border : '1px solid red' }) // Added to help visualise focus, remove this line 
          .focus()
          break
        }
      } 
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

    <div class="row">
     <div class="col-3 pr-0">
      <div class="form-group">
       <label for="txtBarcode">Barcode</label>
       <input type="text" id="txtBarcode" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
     <div class="col-7 pl-2 pr-0">
      <div class="form-group">
       <label for="txtPartDesc">Description</label>
       <input type="text" id="txtPartDesc" name="part_desc" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
     <div class="col-2 pl-2">
      <div class="form-group">
       <label for="txtUom">UoM</label>
       <input type="text" id="txtUom" name="barcode" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
    </div>
    <div class="row">
     <div class="col-4 pr-0">
      <div class="form-group">
       <label for="txtQuantity">Quantity</label>
       <input type="text" id="txtQuantity" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
    </div>

Upvotes: 0

Patrick Evans
Patrick Evans

Reputation: 42746

next(), nextAll(), and the other similar methods are for finding siblings. Since none of your inputs are actual siblings this will not work.

What you can do however is:

  1. Get a jQuery object of all the enabled inputs

    var enabledInputs = $("input:enabled");
    
  2. Get the index of the current input in that jQuery object using index()

    var idx = enabledInputs.index(this);
    
  3. Then using that index get the element at index+1 using eq()

    enabledInputs.eq(idx+1).focus();
    

Demo

$(":input").keydown(function(event){
    if (event.keyCode === 13) {
      var enabledInputs = $("input:enabled");
      var idx = enabledInputs.index(this);
      enabledInputs.eq(idx+1).focus()
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

    <div class="row">
     <div class="col-3 pr-0">
      <div class="form-group">
       <label for="txtBarcode">Barcode</label>
       <input type="text" id="txtBarcode" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
     <div class="col-7 pl-2 pr-0">
      <div class="form-group">
       <label for="txtPartDesc">Description</label>
       <input type="text" id="txtPartDesc" name="part_desc" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
     <div class="col-2 pl-2">
      <div class="form-group">
       <label for="txtUom">UoM</label>
       <input type="text" id="txtUom" name="barcode" value="" class="form-control form-control-sm" disabled>
      </div>
     </div>
    </div>
    <div class="row">
     <div class="col-4 pr-0">
      <div class="form-group">
       <label for="txtQuantity">Quantity</label>
       <input type="text" id="txtQuantity" name="barcode" class="form-control form-control-sm">
      </div>
     </div>
    </div>

Upvotes: 3

CertainPerformance
CertainPerformance

Reputation: 371233

The next input is not a sibling of the #barcode input, so nextAll won't work at that point. Try navigating to the parent's parent, the div class="col-, and then use nextAll to recursively search through that parent's siblings until a matching element is found:

$(":input").keydown(function(event) {
  if (event.keyCode !== 13) return;
  $(this)
    .parent()
    .parent() // get to the `class=col-#` element
    .nextAll(':input:enabled')
    .first()
    .focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />

<div class="row">
  <div class="col-3 pr-0">
    <div class="form-group">
      <label for="txtBarcode">Barcode</label>
      <input type="text" id="txtBarcode" name="barcode" class="form-control form-control-sm">
    </div>
  </div>
  <div class="col-7 pl-2 pr-0">
    <div class="form-group">
      <label for="txtPartDesc">Description</label>
      <input type="text" id="txtPartDesc" name="part_desc" value="" class="form-control form-control-sm" disabled>
    </div>
  </div>
  <div class="col-2 pl-2">
    <div class="form-group">
      <label for="txtUom">UoM</label>
      <input type="text" id="txtUom" name="barcode" value="" class="form-control form-control-sm" disabled>
    </div>
  </div>
</div>
<div class="row">
  <div class="col-4 pr-0">
    <div class="form-group">
      <label for="txtQuantity">Quantity</label>
      <input type="text" id="txtQuantity" name="barcode" class="form-control form-control-sm">
    </div>
  </div>
</div>

Upvotes: 0

Related Questions