Nikk
Nikk

Reputation: 7891

Auto Selecting the next Input field and going Back

Once inputed, a user can't go back to change their input.

$("form").on("keyup change paste", function(e) {
  e.preventDefault();

  var a = $(this).find("input[type='text'].a");
  var b = $(this).find("input[type='text'].b");
  var c = $(this).find("input[type='text'].c");
  var d = $(this).find("input[type='text'].d");
  var e = $(this).find("input[type='text'].e");
  var f = $(this).find("input[type='text'].f");

  a.val(a.val().replace(/[^0-9]/g, ""));
  b.val(b.val().replace(/[^0-9]/g, ""));
  c.val(c.val().replace(/[^0-9]/g, ""));
  d.val(d.val().replace(/[^0-9]/g, ""));
  e.val(e.val().replace(/[^0-9]/g, ""));
  f.val(f.val().replace(/[^0-9]/g, ""));

  if (a.val().length == a.attr('maxlength')) {
    a.next("input").focus();
  }
  if (b.val().length == a.attr('maxlength')) {
    b.next("input").focus();
  }
  if (c.val().length == a.attr('maxlength')) {
    c.next().next("input").focus();
  }
  if (d.val().length == a.attr('maxlength')) {
    d.next("input").focus();
  }
  if (e.val().length == a.attr('maxlength')) {
    e.next("input").focus();
  }
  if (f.val().length == a.attr('maxlength')) {
    f.next("input").focus();
  }
});
input {
  width: 20px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form name="code" action="*" method="post" autocomplete="off">
  <input type="text" name="code" maxlength="1" autocomplete="off" class="a">
  <input type="text" name="code" maxlength="1" autocomplete="off" class="b">
  <input type="text" name="code" maxlength="1" autocomplete="off" class="c">
  <span>—</span>
  <input type="text" name="code" maxlength="1" autocomplete="off" class="d">
  <input type="text" name="code" maxlength="1" autocomplete="off" class="e">
  <input type="text" name="code" maxlength="1" autocomplete="off" class="f last">
</form>

How can that be done?

And is there a more elegant approach to mine above?


Live: jsFiddle

Upvotes: 3

Views: 980

Answers (3)

Cat
Cat

Reputation: 4226

Clearing the inputs on focus would do it. (I don't use jQuery much, so apologies if I have any incorrect syntax.)

$("form").focus(function() {

    var a = $(this).find("input[type='text'].a")
    var b = $(this).find("input[type='text'].b") // ...etc  

    a.val("");
    b.val(""); // ...etc
});

That said, Utkanos is 100% correct that a loop is the right way to handle both issues (auto-advancing and allowing edits).

Upvotes: 0

Orelsanpls
Orelsanpls

Reputation: 23515

My idea would be to focus next, and loop when arriving at the last one. Replace the number in case of a new entry.

// init the html
const nbInput = 6;

let html = '';

for (let i = 0; i < nbInput; i += 1) {
  html += `<input type="text" name="code" maxlength="1" autocomplete="off" number="${i}">`;
}

$('form').html(html);

$('form input').on('keypress', function(e) {
  e.preventDefault();
  
  // Ignore bad values
  if (/^[^0-9]$/g.test(String.fromCharCode(e.which))) {
    return;
  }

  // Replace the actual value with the keypressed one
  $(this).val(String.fromCharCode(e.which));

  // Reset & focus next
  if ($(this).val() !== '' && Number($(this).attr('number')) < (nbInput - 1)) {
    $(`input[number=${Number($(this).attr('number')) + 1}]`).focus();
  } else {
    // Focus the first item when we finished
    $('input[number="0"]').focus();
  }
});
input {
  width: 20px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form name="code" action="*" method="post" autocomplete="off">
</form>

Upvotes: 0

Mitya
Mitya

Reputation: 34556

Any time you find yourself finding very repetitious code, always think LOOP.

The below will allow the user to edit their values. It also greatly reduces your code.

$('form').on('input', e => {
    var letters = ['a', 'b', 'c', 'd', 'e', 'f'];
    letters.forEach(letter => {
        let field = $(e.target);
        field.val(field.val().replace(/[^0-9]/g, ''));
        if(field.val().length == field.attr('maxlength')) { field.nextAll('input').first().focus(); }
    });
});

Fiddle.

Notes:

  • Listen for the input event; it has the advantage of covering all the events you were listening for, and, crucially, fires after keypress (meaning you can be sure of grabbing the latest, complete value from the field)
  • avoid repetitious code; the loop allows us to write the business logic once rather than repeatedly
  • there is no need to prevent the event's default action
  • by using nextAll('input').first(), we can be sure of getting the next input, whether it's the next sibling or, as is the case with the third input, separated by another type of element

Upvotes: 3

Related Questions