4

I have a really odd problem on a project. Long Story Short, I have input fields that record interest rate, so a % is appended on blur and removed on focus. It works fine on every browser except for IE11. For some reason, it moves the cursor to the beginning of the input, which is annoying for people tabbing through and typing in values quickly.

Here is a simplified example in:

$('#test').val('default');

$('#test').focus(function() {
    var value = $(this).val().slice(0, -1);
    $(this).val(value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="test" />

Again, this only happens in IE11 (works fine in older versions of IE). Has anyone run into this issue before? I tried forcing focus again after the value is reassigned, but that didn't solve the issue. Any tips are appreciated.

sbatson5
  • 648
  • 11
  • 19

2 Answers2

3

You could try to set caret position manually when appending/removing % mark, using those two functions (those are pretty generic and should work for every browser if you need setting caret positions for all browsers some other time):

function getCaretPosition(element) {
  var caretPos = 0;
  if (element.type === 'text' || element.type === 'tel') {
    if (document.selection) { // IE Support
      element.focus();
      var Sel = document.selection.createRange();
      Sel.moveStart('character', -element.value.length);
      caretPos = Sel.text.length;
    } else if (element.selectionStart || element.selectionStart === '0') {// Firefox support
      caretPos = element.selectionStart;
    }
  }

  return caretPos;
}

function setCaretPosition(element, position) {
  if (element.type === 'text' || element.type === 'tel') {
    if (element.setSelectionRange) {
      element.focus();
      element.setSelectionRange(position, position);
    } else if (element.createTextRange) {
      var range = element.createTextRange();
      range.collapse(true);
      range.moveEnd('character', position);
      range.moveStart('character', position);
      range.select();
    }
  }
}

And call them only when using IE11 :) Also, if you want, you could make those functions more specific, removing parts for FF :)

SzybkiSasza
  • 1,591
  • 12
  • 27
  • 1
    Thanks for the reply. Tried that in a fiddle and the issue still persists: https://jsfiddle.net/n4zqn3y5/1/ – sbatson5 Jul 09 '15 at 16:05
  • Try to get caret position before doing anything with the field and then set it accordingly after operations, not in one operation :) Your code essentially just puts caret position where it is at the moment. Another way is to set caret at the end of the string - using `.val().length`. – SzybkiSasza Jul 09 '15 at 16:07
  • https://jsfiddle.net/n4zqn3y5/3/ Just tried that, actually. Still running into the issue. And it clearly is returning the right length... – sbatson5 Jul 09 '15 at 16:23
  • Those functions operate on pure DOM nodes, change your function call to: `setCaretPosition(this, $(this).val().length);` instead of using `$(this)` and it should work right away. – SzybkiSasza Jul 09 '15 at 16:33
  • Awesome. Thank you for solving this for me. It was a minor, but very annoying issue. – sbatson5 Jul 09 '15 at 17:10
0

This issue can be solved by:

  • getting a reference to the input element
  • adding an onfocus event handler

Then setting the selection range in the onfocus handler to the end of the input value, like so:

const onFocus = (el) => {
  const { value } = el.value
  el.setSelectionRange(value.length, value.length);
}

<input type='text' onfocus='onFocus(this)'  />

If you are using ReactJS, here is that solution.

hanorine
  • 7,256
  • 3
  • 14
  • 18