You can find very detailed explainations in this Codepen
This solution is simple and will only allow one dot in the number field. It doesn't prevent from clicking back in the number and adding numbers before the "."
. It doesn't prevent from executing browser keyboard shortcuts like refresh, copy and pasting (as long as the pasted value is a valid number) and others. It will allow to add "."
withing the body of the number, but will remove any exceeding floats over the set limit.
The only behavior that I still can't prevent is if you press the dot key at the end of the input repeatedly, the dot will blink on and off. This happens because a typed value of "13."
is a valid number and returns "13"
and a typed value of "13.."
is not and returns "". In my solution, if a value returns ""
without the press of backspace or delete, it gets rolled back to the last valid value, wich is "13"
, obtained from the typed value "13."
.
I've tried solutions where if a dot was pressed once, it was prevented to be triggered a second time, but every time I managed to get stuck with pressing the dot right after an already existing dot followed by nothing and then get stuck with not being able to type a dot unless I pressed any other key first.
I think the blinking on multiple press is the best solution for ther's no way a user would type a dot and nothing happens.
let lastValidInputValue;
let selectedDot = false;
const onKeypress = (e) => {
if (e.key === "." && e.target.value.indexOf(".") !== -1 && !selectedDot) e.preventDefault();
selectedDot = false;
if (e.key === "e") e.preventDefault();
};
const onInput = (e) => {
if (
e.target.value.indexOf(".") < e.target.value.length - e.target.getAttribute("data-toFixed") - 1 &&
e.target.value.indexOf(".") !== -1
) {
let newValue;
newValue = e.target.value.slice(
0,
e.target.value.indexOf(".") +
parseInt(e.target.getAttribute("data-toFixed")) +
1
);
newValue = parseFloat(newValue);
e.target.value = newValue;
}
if (e.target.value !== "") {
lastValidInputValue = e.target.value;
} else if (e.inputType.match(/delete/g)) {
lastValidInputValue = "";
} else {
e.target.value = lastValidInputValue;
}
};
const onSelect = (e) => {
if(window.getSelection().toString().indexOf(".") > -1) selectedDot = true;
}
<input type="number" id="myNumber" name="myNumber" data-toFixed="2" step="any" onkeypress="onKeypress(event)" oninput="onInput(event)" onselect="onSelect(event)">
input type="number"
will be able to use or adapt the code presented here. – Burneye.target.value.toString()
on a number input field containing"13."
returns"13"
so doing.indexOf('.')
on it is useless and will let the keypress happen... It could also prevent keyboard shortcuts with other modifiers than ctrl. preventing default in bulk is a bad accessibility solution. – Perpetual