FireFuro99
FireFuro99

Reputation: 393

Input with type="number" that allows only numbers to be typed

I want to make an Input-Field in which you can only write natural numbers. (Yes, I know this can be a bad practice, as the user doesn't get any feedback). If you type anything else than a digit, it should not appear in the input. I want to use plain JavaScript (no JQuery).

This is how I'd do it normally:

<input oninput="this.value = this.value.replace(/\D+/g, '')">

But I found out, that <input type="number"> is much preferred for mobile devices, as it doesn't show the whole keyboard, but just digits.

So my question is, how can I combine type="number" with the filtering (and make it compatible with Cut/Copy/Paste)?

The value of the <input type="number">-element is always an empty String if any non-number-character is entered. So my filtering method from above doesn't work. Is there any workaround?

If not, I'd have to listen for keydown, paste, cut, and possibly many more events. Which events would I have to consider, how would I implement it, and is there any easier way I have overlooked?

Upvotes: 8

Views: 39988

Answers (4)

TheLooseCannon
TheLooseCannon

Reputation: 376

<input onkeydown=this.isNumberInputOnly />

and the function

function isNumberOnlyInput(event) {
    if (!parseInt(event.key) && event.key != 'Backspace') {
        event.preventDefault();
    }
}

can roughly do the trick

Upvotes: 1

BeerusDev
BeerusDev

Reputation: 1519

Here is a solution using HTML and vanilla JS:

function setInputFilter(textbox, inputFilter) {
  ["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop"].forEach(function(event) {
    textbox.addEventListener(event, function() {
      if (inputFilter(this.value)) {
        this.oldValue = this.value;
        this.oldSelectionStart = this.selectionStart;
        this.oldSelectionEnd = this.selectionEnd;
      } else if (this.hasOwnProperty("oldValue")) {
        this.value = this.oldValue;
        this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
      } else {
        this.value = "";
      }
    });
  });
}

setInputFilter(document.getElementById("numTxtBox"), function(value) {
  return /^-?\d*$/.test(value); });
  <tr><td>Number Only </td><td><input id="numTxtBox"></td></tr>

UPDATE:

The above code does malfunction in Firefox and Chrome.

Here is an alternate solution that works across all browsers!

function validate(num) {
  var theEvent = num || window.event;

  // Handle paste
  if (theEvent.type === 'paste') {
      var key = event.clipboardData.getData('text/plain');
  } else {
  // Handle key press
      var key = theEvent.keyCode || theEvent.which;
      key = String.fromCharCode(key);
  }
  var regex = /[0-9]|\./;
  if( !regex.test(key) ) {
    theEvent.returnValue = false;
    if(theEvent.preventDefault) theEvent.preventDefault();
  }
}
<input type='number' onkeypress='validate(event)' onpaste='validate(event)' />

Upvotes: 3

mplungjan
mplungjan

Reputation: 178413

Tested in Chrome (cannot enter anything else than numbers, - and e

In Firefox you can type but not submit

Try typing anything and then hit enter
<form>
<input type="number" required />
</form>

Let's try this then - if it is ok to clear the field when typing a char, we do not need keyUp or such

Firefox will return empty string if you type a char anywhere, Chrome will not allow the char

document.querySelector("form").addEventListener("input",function(e) {
  const tgt = e.target;
  if (tgt.type && tgt.type==="number") { 
    const val = tgt.value;
    const nums = val.replace(/[^\d.-]/g, '');
    if (!/\d+/.test(val)) tgt.value="";
  }  
})
Try typing anything and then hit enter
<form>
<input type="number" required />
</form>

Upvotes: 3

User863
User863

Reputation: 20039

Try using inputmode attribute

https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode

<input inputmode="numeric" oninput="this.value = this.value.replace(/\D+/g, '')"  />

References

https://css-tricks.com/finger-friendly-numerical-inputs-with-inputmode

Upvotes: 14

Related Questions