unpollito
unpollito

Reputation: 1019

HTML input that takes only numbers and the + symbol

I am trying to build a custom text input for phone numbers that accepts only numbers and the plus (+) symbol; all other characters need to be discarded and not shown on the field.

I am trying to do this using an event handler (onkeydown/onkeypress) and discarding inputs corresponding to other keys. However, I can't figure out a cross-browser way to do it. Here are the approaches that I have tried and don't work:

Thanks!

Upvotes: 19

Views: 29090

Answers (7)

Aramil Rey
Aramil Rey

Reputation: 3475

Always try to make server-side validation, this is meant to 'help' the user, not to validate the data, (You can always open up your console and change the value of the input value however you want)

Now, the method I would use is:

Check the value of the whole input on change and make that value go trough a regex to clean unwanted chars, while keeping track of where the "text cursor" was

const tel = document.getElementById('tel');

tel.addEventListener('input', function() {
  let start = this.selectionStart;
  let end = this.selectionEnd;
  
  const current = this.value
  const corrected = current.replace(/([^+0-9]+)/gi, '');
  this.value = corrected;
  
  if (corrected.length < current.length) --end;
  this.setSelectionRange(start, end);
});
<input type="tel" id="tel">

You could make a much more 'accurate' regex according to what you want, here is a nice tool for that: RegExr

Upvotes: 9

R3tep
R3tep

Reputation: 12864

There is another solution, you can use Array.prototype.filter() to remove the bad characters, and Array.prototype.join() to recreate the string before insert it into the input.

You can use oninput event. It execute a JavaScript when a user writes something in an <input> field.


See example below

var inputEl = document.getElementById('tel');
var goodKey = '0123456789+ ';

var checkInputTel = function(e) {
  var key = (typeof e.which == "number") ? e.which : e.keyCode;
  var start = this.selectionStart,
    end = this.selectionEnd;

  var filtered = this.value.split('').filter(filterInput);
  this.value = filtered.join("");

  /* Prevents moving the pointer for a bad character */
  var move = (filterInput(String.fromCharCode(key)) || (key == 0 || key == 8)) ? 0 : 1;
  this.setSelectionRange(start - move, end - move);
}

var filterInput = function(val) {
  return (goodKey.indexOf(val) > -1);
}

inputEl.addEventListener('input', checkInputTel);
<input type='tel' id='tel' />


Note : I use input type tel to show default number pad in a smartphone or a tablet.

tel: A control for entering a telephone number; line-breaks are automatically removed from the input value, but no other syntax is enforced. You can use attributes such as pattern and maxlength to restrict values entered in the control. The :valid and :invalid CSS pseudo-classes are applied as appropriate.

Reference : MDN <input>

Upvotes: 17

le_m
le_m

Reputation: 20238

This robust generic approach is inspired by @R3tep's answer. It allows to define regexp patterns via the data-filter attribute similar to the pattern attribute:

// Apply filter to all inputs with data-filter:
let inputs = document.querySelectorAll('input[data-filter]');

for (let input of inputs) {
  let state = {
    value: input.value,
    start: input.selectionStart,
    end: input.selectionEnd,
    pattern: RegExp('^' + input.dataset.filter + '$')
  };
  
  input.addEventListener('input', event => {
    if (state.pattern.test(input.value)) {
      state.value = input.value;
    } else {
      input.value = state.value;
      input.setSelectionRange(state.start, state.end);
    }
  });

  input.addEventListener('keydown', event => {
    state.start = input.selectionStart;
    state.end = input.selectionEnd;
  });
}
<input type='tel' data-filter='[0-9|+]*' placeholder='123+456'>
<input type='tel' data-filter='(\+|(\+[1-9])?[0-9]*)' placeholder='+10123'>
<input type='text' data-filter='([A-Z]?|[A-Z][a-z]*)' placeholder='Abcdefg'>
<input type='text' data-filter='([A-Z]{0,3}|[A-Z]{3}[0-9]*)' placeholder='ABC123'>

Upvotes: 10

A.Sharma
A.Sharma

Reputation: 2799

Using a combination of a keyup event listener, some RegEx/String comparison methods, and an intermediate variable, I was able to come up with the following:

var ele = document.getElementById('phone');
var curr = "";
var regexPatt = /^(0|[1-9][0-9]*)$/;
ele.addEventListener('keyup',function(e){
  var code = e.keyCode || e.which;
  if(this.value.match(regexPatt) || this.value.indexOf('+') > -1 || code == 8){
    curr = this.value;
    this.value = curr;
  } else {
    this.value = curr;
  }
});

Take a look at the fiddle: https://jsfiddle.net/Lg31pomp/2/

This seems to work with digits, the + character as well as if the user backspaces the input element.

Upvotes: 2

Ivan Gajic
Ivan Gajic

Reputation: 486

Your input should look something like this:

<input type="text" onkeypress='return isNumberKey(event);'>

and this is the script:

function isNumberKey(evt) {
    var charCode = (evt.which) ? evt.which : event.keyCode;
    console.log(charCode);
    if (charCode != 43 &&  charCode > 31
        && (charCode < 48 || charCode > 57))
        return false;

    return true;
}

This is one of the many possible solutions.

Upvotes: -1

bhagya
bhagya

Reputation: 103

use input

type="tel" or "phone"

It Shows default number pad in mobiles.

Hope this will help :)

Upvotes: 6

yeouuu
yeouuu

Reputation: 1913

I suggest you look at this project. https://github.com/igorescobar/jQuery-Mask-Plugin/

You could use it as is: $('.phone').mask('0000-0000'); Example: https://igorescobar.github.io/jQuery-Mask-Plugin/

Or you could read the source code and check out how they solve it.

Upvotes: 8

Related Questions