40

I added the code below to select whole text when user click on input box:

<input type="number" onclick="this.setSelectionRange(0, this.value.length)" name="quantity" />

But I receive the error below:

Uncaught InvalidStateError: Failed to execute 'setSelectionRange' on 'HTMLInputElement': The input element's type ('number') does not support selection.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Nick Mehrdad Babaki
  • 11,560
  • 15
  • 45
  • 70

7 Answers7

23

Use input type="tel" instead.

For your example:

<input type="tel" onclick="this.setSelectionRange(0, this.value.length)" name="quantity" />

That will do the trick and avoid the error message.

And on mobile phones, it shows up the desired number pad.

Avatar
  • 14,622
  • 9
  • 119
  • 198
23

I know this is an old question, but I did find a good workaround without using the tel input type. By changing the input type from number to text before the selection, the error goes away and you get to keep all the benefits of the number input type.

  • tel allows text input, which may not work with numbers.
  • tel does not show the number "spinner" next to the input (only if you want it).
function onInputFocus(event) {
  const target = event.currentTarget;

  target.type = 'text';
  target.setSelectionRange(0, target.value.length);
  target.type = 'number';
}
Tri Q Tran
  • 5,500
  • 2
  • 37
  • 58
  • Nice! One warning is that if this function is going to be used on several inputs, some text and some number, make sure to only change the target.type to number at the end, if that's what it was at the beginning. But, good solution. – rossdavidh Sep 26 '19 at 15:38
  • 2
    Doesnt work for me on type Email, as soon as I set it back to email the selection gets away. – Michael Baarz Nov 10 '20 at 22:23
5

As a variation of Tri Q Tran's answer and make it a more generic one. This may be a better approach:

const element = document.createElement('input');
element.type = 'number';

(function(originalFn){
    element.setSelectionRange = function() {
        this.type = 'text';
        originalFn.apply(this, arguments);
        this.type = 'number';
    }
})(element.setSelectionRange);

Or if you don't mind contaminating the prototype, this is a more generic solution:

(function(originalFn){
    HTMLInputElement.prototype.setSelectionRange = function() {
        if ( this.type === 'number' ) {
            this.type = 'text';
            originalFn.apply(this, arguments);
            this.type = 'number';
        } else {
            originalFn.apply(this, arguments);
        }
    }
})(HTMLInputElement.prototype.setSelectionRange);
Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48
4

input type="number" doesn't support setSelectionRange

You can use: type="text" and inputmode="numeric", This will show a numeric keyboard for mobile users and supports setSelectionRange

    <input 
     type="text"
     inputmode="numeric"
     onclick="this.setSelectionRange(0, this.value.length)" 
     name="quantity" />
Harish Kulkarni
  • 1,481
  • 11
  • 18
3

Just like the error message says, you can't use setSelectionRange with a number input. If you want to modify the selection using JavaScript, you'll have to use <input type="text"/> instead.

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
3

The evt.target.select() selects content of input type="number" in Chrome, the "if" structure does the same on touch devices.

document.querySelector('.number_input').addEventListener('focus', function (evt) {
    evt.target.select();
    if ('ontouchstart' in window) {
      setTimeout(function() {
        evt.target.setSelectionRange(0, 9999);
      }, 1);
    }
}, true);

Unfortunately that "if" prevents that autoselect in Mac Safari, I don't know how to get the same result both in desktop browsers and mobile.

1

I kind of got this working in angular 1.5 using a nifty custom directive (see example below in typescript).

Since it appears there is no way to programmatically select the entire value while the input type="number", the strategy here is to temporarily change the input type from number to text while editing the value, then change it back to the original type on blur.

This results in behavior that differs slightly from the native behavior in that it will actually allow you to type in "invalid" data into the field. However, on blur, all of the browser's native number validation logic will kick in and prevent any invalid data from being submitted. I'm sure there's some other gotchas but it's works well enough in Chrome and FireFox for us so I thought I'd share.

/// Selects the entire input value on mouse click. 
/// Works with number and email input types.
export class SelectOnClick implements ng.IDirective {
    require = 'ngModel';
    restrict = 'A';
    private ogType: any

    constructor(private $window: ng.IWindowService) { }

    link = (scope: ng.IScope, element: any) => {

        element.on('click', () => {
            if (!this.$window.getSelection().toString()) {      
                this.ogType = element[0].type;
                element[0].type = 'text';
                element[0].setSelectionRange(0, element[0].value.length);
            }
        })

        element.on('blur', () => {
            element[0].type = this.ogType;
        })
    }

    static factory(): ng.IDirectiveFactory {
        var directive = ($window: ng.IWindowService) => new SelectOnClick($window);
        directive['$inject'] = ['$window'];
        return directive;
    }
} 
nub340
  • 51
  • 5