Prevent input type=“number” from getting more than one dot in its value and limit decimals numbers
Asked Answered
P

1

0

Inbefore: I know this question has been asked more than once on this forum. I know I could post my answer on these other posts. My issue is that the users who asked those questions did it 3 - 4 years ago, and looking at their autors profile, they do not seem very active and I beleive the questions would never be marked as solved.

So I've been looking around every where to find help on doing exactly that, with no simple solutions allowing to limit the user from typing more than one dot in an input type=“number”. It is important to keep the input type="number" as it may affect the keyboard on certain mobile devices.

I know it might seem limitative to prevent a keyboard event, and some might argue that the field should only be evaluated on submit or on change or on blur. I say the input type="number" already limits the effects of certain keypresses that are anything but numbers or "e" or ".", and that happens on the fly.

On top of it, some solutions made it impossible to limit the amount of floats allowed.

Perpetual answered 28/5, 2020 at 17:18 Comment(7)
That's not how Stack Overflow works. Questions are not marked as "solved". An answer may be marked as "accepted", but that only means something to the asker, no one else. The age of the question makes no difference unless there are fundamental changes in the environment (e.g., the question was specifically asking about version 1.22 and the answer requires 43.71). In this case, any question asking about input type="number" will be able to use or adapt the code presented here.Burney
Does this answer your question? Prevent typing non-numeric in input type numberBurney
No it doesn't as it doesn't prevent multiple dots to be typed.Perpetual
It simply doesn't allow for dots to be typed, nor numbpad numbers, wich is even worse.Perpetual
By "it" I assume you're referring to the accepted answer. As mentioned, the accepted answer is only relevant to the asker; it is the answer that help them the most. There are 10 other answers to that question. For example, this one which does everything you're looking for.Burney
Sadly not, since e.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
So add your answer to that duplicate question.Burney
P
0

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)">
Perpetual answered 28/5, 2020 at 17:18 Comment(2)
how to make the number behind the decimal point more than two?Retrace
oh, I see u just need to change data to fixed in input form.Retrace

© 2022 - 2024 — McMap. All rights reserved.