In putting together a small webapp, I'm trying to ensure that end users are unable to place invalid characters in a number field that can hold signed floats. I'm using Dojo to search on an applied CSS class (in this case, ogInputNumber
) and set events on input, keyup, and blur.
Ideally, I would like the input to be type="number"
and to only allow digits, a hyphen (for signed floats), and a period character to act as a decimal place. If a user includes more than one hyphen or period character, the JS should truncate that second invalid character and everything thereafter in the input. Unfortunately, the JS behaves differently depending on whether the input is type="number"
or type="text"
.
For type="text"
, if I attempt to enter the text 2.6a
, 2.6
is fine, but the a
is caught on the input event and prevented from appearing in the input. This is the desired behavior, but I would like to have the input as type="number"
so the number spinners appear and for ease of use with mobile devices (so the number keyboard is brought up by default).
For type="number"
, if I attempt to enter the text 2.6a
, the 2.6
is allowed to remain, but as soon as a
is typed, the entire field is cleared out. That will prevent any invalid characters, but it's annoyingly overzealous. I've replicated this behavior on Chrome, Firefox, IE11, and Opera.
Can anyone offer any suggestions as to why the JS operates differently between inputs with type="text"
and those with type="number"
?
HTML:
<p>
<label for="numberInput1">Text Input</label>
<input id="numberInput1" class="ogInputNumber" type="text" />
</p>
<p>
<label for="numberInput2">Number Input</label>
<input id="numberInput2" class="ogInputNumber" type="number" />
</p>
JS:
// Checks number input fields for proper formatting
require(["dojo/domReady!", "dojo/on", "dojo/query"],
function (ready, on, query) {
query(".ogInputNumber").forEach(function (node) {
// Replace all the non-numeric, non-period, and non-hyphen characters with nothing while the user is typing
on(node, "input, keyup", function () {
this.value = this.value.replace(/[^\d\.-]/g, '');
});
// When the user leaves the input, format it properly as a signed float (or zero if it's something weird)
on(node, "blur", function () {
try {
if (this.value) {
this.value = parseFloat(this.value).toString();
} else {}
} catch (error) {
this.value = 0;
}
});
});
});
Working JSFiddle: http://jsfiddle.net/etehy6o6/1/
I think that's the default behavior of number input type, but I'm not sure. It's logical to think the input should not let the user put anything that is not a number, so it clears all the value before you can fire your keyup event.
So to keep the last valid value declare a variable outside the scope of your event and set it to the replaced value that was not cleared because invalid key input.
Using the code in your Fiddle:
Edited because addressed bug in comments
HTML
Javascript