How can I retain the expected cursor position when auto formatting a number with commas?

Viewed 663

I have an input where I want to replace the value of the number on keyup event. Using Intl.NumberFormat().format(num); to accomplish this.

All is fine and it works great until you click inside of the already formatted value and start adding more numbers, the cursor jumps.

I tried to solve this by setting the cursor, but it still behaves badly.

In short, how can I change this snippet so that no matter where you edit the value, the cursor remains in the expected position?

const input = document.getElementById("foo");
input.addEventListener("keyup", handleKeyUp);

function handleKeyUp(e) {
    const num = e.target.value.replace(/,/g, "");
  const formatted = new Intl.NumberFormat().format(num);
  
  var cursor = e.target.selectionStart;// + 1;
  input.value = formatted;
  e.target.setSelectionRange(cursor, cursor);
}

// Try the following
// 1) 123456789
// 2) 123
// 3) place cursor between the 1 and 2 and add a number

// If I ++cursor then #1 is resolved
// And #2 initially appears to be resolved unless I keep going with more numbers
<input id="foo" type="text">

1 Answers

Not a very elegant solution, but I moved the cursor based on if a comma was added/removed from the text field (left or right respectively).

See snippet below:

const input = document.getElementById("foo");
input.addEventListener("keyup", handleKeyUp);
let commas = 0;

function handleKeyUp(e) {
  const num = e.target.value.replace(/,/g, "");
  const formatted = new Intl.NumberFormat().format(num);
  // get total commas in number
  let totalCommas = (formatted.match(/,/g) || []).length;
  var cursor = e.target.selectionStart;
  
  if(commas > totalCommas) {
    //shift cursor to the left (a comma was removed)
    commas--;
    cursor--;
  } else if (commas < totalCommas){
    // shift cursor to the right (a comma was added)
    commas++;
    cursor++;
  }
  
  input.value = formatted;
  e.target.setSelectionRange(cursor, cursor);
}

// Try the following
// 1) 123456789
// 2) 123
// 3) place cursor between the 1 and 2 and add a number

// If I ++cursor then #1 is resolved
// And #2 initially appears to be resolved unless I keep going with more numbers
<input id="foo" type="text">

Related