1

I have an <input type="number" /> and I want to prevent any non-numeric characters from being entered.

<input id="app-client-id" type="number" pattern="[0-9]+" />

For preventing regular keypresses, this can be done with

const validKeys = new Set([
    'home',
    'end',
    'pageup',
    'pagedown',
    'delete',
    'backspace',
    'arrowleft',
    'arrowright',
]);

function isValidKeypress(e) {
    // numeric characters
    if (e.charCode >= 48 && e.charCode <= 57) {
        return true;
    }

    if (e.key && validKeys.has(e.key.toLowerCase())) {
        return true;
    }

    // for allowing select all, copy, and paste
    if (e.ctrlKey) {
        return true;
    }

    return false;
}

$('#app-client-id').on('keypress', isValidKeypress);

Now all that's left is preventing pasting non-numeric characters, or ideally, filtering out non-numeric characters.

function filterPastedText(e) {
    let clipboardData = e.originalEvent.clipboardData,
        text = clipboardData.getData('text').replace(/[^\d]/g, '');
    clipboardData.setData('text', text);
}

$('#app-client-id').on('paste', filterPastedText);

This works in Chrome/Webkit. In Firefox, however, it throws an error on setData():

NoModificationAllowedError: Modifications are not allowed for this document

Any ideas on how to tell the browser to allow calling setData()?

If such a method does not exist, is there a way to manually "paste" the filtered value into the input at the right cursor position (and replacing selected text, if there is any) without using a hidden textarea? I'm having trouble detecting the position of the cursor in an input element, regardless of whether text is selected; myInput.selectionStart is always null.

Edit

It turns out calling setData() does not, in fact, work in Chrome. Setting the type to number automatically filtered out non-numeric characters except 'e', '-', and '.', and the string I was testing it on, did not include any of those characters. Calling setData() simply fails silently.

dx_over_dt
  • 13,240
  • 17
  • 54
  • 102
  • I've got not an answer, but another puzzle for you: I started playing around with filtering out non-numeric input myself, and found out that on my Mac, I couldn't filter out accented characters like `é` anyway but checking after an `oninput` event. There's never even a `keypress` event corresponding to the character being entered. – kshetline Apr 30 '18 at 01:43

1 Answers1

0

One approach you can take is to simply allow unwanted characters to momentarily enter the input field, but monitor oninput events, check the value of the input field for the unwanted characters at each event, and if any are found, update the input field with a filtered version of its value.

Update:

I've discovered that, ironically, it's harder to limit keyboard input to digits when you create an input as type="number" rather than type="text". Why? Because when you use type="number" non-numeric input can still slip by, but you don't get to see those characters in the value of the input field -- the value is either a valid number, or it's an empty string. That gives you no opportunity to filter the input and keep the valid digits that might be there.

I've created a Plunker with the current state of my own attempts to limit a text field to numeric input: http://plnkr.co/edit/xsVQG1EzsDLMt8POCJUX?p=preview

kshetline
  • 12,547
  • 4
  • 37
  • 73