chrome setSelectionRange() not work in oninput handler
Asked Answered
F

5

13

I'm working with some auto-completion code. setSelectionRange() is used to select text been completed in oninput event handler. It works at least in Firefox 14, but not in Chrome(6, 17).

Simplified code snippet demonstrating the problem is like this:

<input type='text' oninput='select()' />
function select(e){
    var s = this.value;
    if (s.length)
        this.setSelectionRange(s.length-1, s.length);
}

I debugged the code in chrome, and it turns out that text has been selected at first right after the setSelectionRange() been executed, but the selection disappeared later.

If i bind the handler to onclick instead of oninput, like this:

<input type='text' onclick='select()' />

then both browsers work fine.

Can anyone please give me some clue to make selection work in Chrome?

Flied answered 30/7, 2012 at 14:20 Comment(1)
It might have been that you needed to call this.focus() before the call to setSelectionRange(). See example here developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/…Lagrange
A
20

There are some problems with your code, namely that the parameters passed into the select() function are wrong: this will be window and e will be undefined. Also, using select() as a function name within the oninput attributes causes a problem because select will resolve to the select() method of the input itself. A better approach is usually to set the event handler in script rather than via an event handler attribute.

However, the problem exists even after correcting these issues. Possibly the input event fires before the browser has moved the caret in Chrome. A simple workaround would be to use a timer, although this is sub-optimal because there's a possibility the user will be able to input another character before the timer fires.

Demo: http://jsfiddle.net/XXx5r/2/

Code:

<input type="text" oninput="selectText(this)">

<script type="text/javascript">
function selectText(input) {
    var s = input.value;
    if (s.length) {
        window.setTimeout(function() {
            input.setSelectionRange(s.length-1, s.length);
        }, 0);
    }
}
</script>
Aery answered 30/7, 2012 at 15:4 Comment(4)
This works. I wonder why most search engines' search suggestion only show candidates in the droplist, but never complete user's input and select the completion. Maybe it has something to do with my problem.Flied
The reason this doesn't work the right way in Chrome (without setting a timeout) is because a Chromium bug that's been active for over three years now: code.google.com/p/chromium/issues/detail?id=32865Hedberg
for over a year, I've revisited a piece of code only to give up when it wouldn't work and move onto other things. Such a simple fix...frustrating though.Georgia
Android chrome first forced me to use input events instead of keydown, then forced me to use a timer to set caret position. It works in weird ways, too. For example, when deleting a letter with backspace on desktop, caret position is the same for start and end, let's say: 5-5. However on virtual keyboard, it becomes 4 - 5 for start and end. In the end, I needed to check user's keyboard type, too.Welkin
E
1

    
    
    var $input = document.getElementById('my_id');
    
    $input.onfocus = function () {
       $input.setSelectionRange(0, 7);
    }
    $input.focus();
    
    
<input type='text' id='my_id' value="My text for example." />
Endurant answered 17/5, 2019 at 9:41 Comment(0)
C
1

On Angular for example you can do this:

@ViewChild('input', { static: false }) inputElement: ElementRef;

focus(){    
    setTimeout(() => {
        this.inputElement.nativeElement.focus();
        this.inputElement.nativeElement.setSelectionRange(this.valueInput.length, this.valueInput.length);
    });
}
Chronologist answered 10/1, 2020 at 12:11 Comment(0)
U
0

I think setTimeout does not the best solution. You just need call event handler before use setSelectionRange. i use this:

e.currentTarget.value = previousValue;
onChange(e);
e.currentTarget.setSelectionRange(startPosition, endPosition);
Unsphere answered 23/4, 2020 at 11:29 Comment(0)
M
-1

I'm on React and this worked for me on both Firefox and Chrome. First execute the code for selecting the required substring and then call focus and to make sure it runs last, wrap it in a setTimeout

onFocus={(e: React.FocusEvent<HTMLInputElement>) => {
    e.stopPropagation();

    const start = 0;
    const end = value.lastIndexOf(".");

    if (e.target.setSelectionRange) {
        e.target.setSelectionRange(start, end);
    } else if (typeof e.target.selectionStart !== "undefined") {
        e.target.selectionStart = start;
        e.target.selectionEnd = end;
    }
    setTimeout(() => {
        e.target.focus();
    }, 0);
}}

Mantoman answered 18/12, 2023 at 17:41 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.