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.