patternjavascriptCritical
HTML text input allow only numeric input
Viewed 0 times
inputnumerictextallowonlyhtml
Problem
Is there a quick way to set an HTML text input (``) to only allow numeric keystrokes (plus '.')?
Solution
JavaScript
Update: easier solution seems to use
You can filter the input values of a text `
function setInputFilter(textbox, inputFilter, errMsg) {
[ "input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(e) {
if (inputFilter(this.value)) {
// Accepted value.
if ([ "keydown", "mousedown", "focusout" ].indexOf(e.type) >= 0){
this.classList.remove("input-error");
this.setCustomValidity("");
}
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
}
else if (this.hasOwnProperty("oldValue")) {
// Rejected value: restore the previous one.
this.classList.add("input-error");
this.setCustomValidity(errMsg);
this.reportValidity();
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
else {
// Rejected value: nothing to restore.
this.value = "";
}
});
});
}
return /^\d\.?\d$/.test(value); // Allow digits and '.' only, using a RegExp.
}, "Only digits and '.' are allowed");
outline: 1px solid red;
}
function setInputFilter(textbox, inputFilter, errMsg) {
[ "input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(e) {
if (inputFilter(this.value)) {
// Accepted value.
if ([ "keydown", "mousedown", "focusout" ].indexOf(e.type) >= 0) {
this.classList.remove("input-error");
this.setCustomValidity("");
}
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
}
else if (this.hasOwnProperty("oldValue")) {
// Rejected value: restore the previous one.
this.classList.add("input-error");
this.setCustomValidity(errMsg);
this.reportValidity();
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
else {
// Rejected value: nothing to restore.
this.value = "";
}
});
});
}
// Install input filters.
setInputFilter(document.getElementById("intTextBox"), function(value) {
return /^-?\d*$/.test(value);
}, "Must be an integer");
setInputFilter(document.getElementById("uintTextBox"), function(value) {
return /^\d*$/.test(value);
}, "Must be an unsigned integer");
setInputFilter(document.getElementById("intLimitTextBox"), function(value) {
return /^\d*$/.test(value) && (value === "" || parseInt(value)
TypeScript
Here is a TypeScript version of this.
`function setInputFilter(textbox: Element, inputFilter: (value: string) => boolean, errMsg: string): void {
["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(this: (HTMLInputElement | HTMLTextAreaElement) & { oldValue: string; oldSelectionStart: number | null, oldSelectionEnd: number | null }) {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this
Update: easier solution seems to use
beforeinput event.You can filter the input values of a text `
with the following setInputFilter function (supports Copy+Paste, Drag+Drop, keyboard shortcuts, context menu operations, non-typeable keys, the caret position, different keyboard layouts, validity error message, and all browsers since IE 9):
// Restricts input for the given textbox to the given inputFilter function.function setInputFilter(textbox, inputFilter, errMsg) {
[ "input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(e) {
if (inputFilter(this.value)) {
// Accepted value.
if ([ "keydown", "mousedown", "focusout" ].indexOf(e.type) >= 0){
this.classList.remove("input-error");
this.setCustomValidity("");
}
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
}
else if (this.hasOwnProperty("oldValue")) {
// Rejected value: restore the previous one.
this.classList.add("input-error");
this.setCustomValidity(errMsg);
this.reportValidity();
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
else {
// Rejected value: nothing to restore.
this.value = "";
}
});
});
}
You can now use the setInputFilter function to install an input filter:
setInputFilter(document.getElementById("myTextBox"), function(value) {return /^\d\.?\d$/.test(value); // Allow digits and '.' only, using a RegExp.
}, "Only digits and '.' are allowed");
Apply your preferred style to the input-error class. Here’s a suggestion:
.input-error{outline: 1px solid red;
}
Note that you still must do server side validation!
Another caveat is that this will break the undo stack since it sets this.value directly.
This means that CtrlZ will not work to undo inputs after typing an invalid character.
Demo
See the JSFiddle demo for more input filter examples or run the Stack snippet below:
// Restricts input for the given textbox to the given inputFilter.function setInputFilter(textbox, inputFilter, errMsg) {
[ "input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(e) {
if (inputFilter(this.value)) {
// Accepted value.
if ([ "keydown", "mousedown", "focusout" ].indexOf(e.type) >= 0) {
this.classList.remove("input-error");
this.setCustomValidity("");
}
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
}
else if (this.hasOwnProperty("oldValue")) {
// Rejected value: restore the previous one.
this.classList.add("input-error");
this.setCustomValidity(errMsg);
this.reportValidity();
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
else {
// Rejected value: nothing to restore.
this.value = "";
}
});
});
}
// Install input filters.
setInputFilter(document.getElementById("intTextBox"), function(value) {
return /^-?\d*$/.test(value);
}, "Must be an integer");
setInputFilter(document.getElementById("uintTextBox"), function(value) {
return /^\d*$/.test(value);
}, "Must be an unsigned integer");
setInputFilter(document.getElementById("intLimitTextBox"), function(value) {
return /^\d*$/.test(value) && (value === "" || parseInt(value)
.input-error {
outline: 1px solid red;
}
JavaScript input filter showcase
Supports Copy+Paste, Drag+Drop, keyboard shortcuts, context menu operations, non-typeable keys, the caret position, different keyboard layouts, and all browsers since IE 9.
There is also a jQuery version of this.
Integer
Integer >= 0
Integer >= 0 and <= 500
Float (use . or , as decimal separator)
Currency (at most two decimal places)
A-Z only
Hexadecimal
TypeScript
Here is a TypeScript version of this.
`function setInputFilter(textbox: Element, inputFilter: (value: string) => boolean, errMsg: string): void {
["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
textbox.addEventListener(event, function(this: (HTMLInputElement | HTMLTextAreaElement) & { oldValue: string; oldSelectionStart: number | null, oldSelectionEnd: number | null }) {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this
Context
Stack Overflow Q#469357, score: 1362
Revisions (0)
No revisions yet.