Input Masking a Phone Number

I’m continuing work on software I coded a few months ago and I am trying to mask HTML input for a phone number. I am wanting it to mask from 1234567890 to (123) 456-7890.

My HTML input looks like this:

<div class="form-group">
	<label for="member_phone">Member's Phone Number</label>
	<input type="tel" class="form-control" id="member_phone" name="member_phone" placeholder="(123) 456-7890" maxlength="14" autocomplete="off" onkeydown="javascript:backspacerDOWN(this,event);" onkeyup="javascript:backspacerUP(this,event);"/>
</div>

and my JavaScript looks like this:

var zChar = new Array(' ', '(', ') ', '-', '.');
var maxphonelength = 14;
var phonevalue1;
var phonevalue2;
var cursorposition;

function ParseForNumber1(object){
	phonevalue1 = ParseChar(object.value, zChar);
}
function ParseForNumber2(object){
	phonevalue2 = ParseChar(object.value, zChar);
}

function backspacerUP(object,e) {
	if(e){
		e = e
	} else {
		e = window.event
	}
	if(e.which){
		var keycode = e.which
	} else {
		var keycode = e.keyCode
	}

	ParseForNumber1(object)

	if(keycode >= 48){
		ValidatePhone(object)
	}
}

function backspacerDOWN(object,e) {
	if(e){
		e = e
	} else {
		e = window.event
	}
	if(e.which){
		var keycode = e.which
	} else {
		var keycode = e.keyCode
	}
	ParseForNumber2(object)
}

function GetCursorPosition(){

	var t1 = phonevalue1;
	var t2 = phonevalue2;
	var bool = false
    for (i=0; i<t1.length; i++)
    {
    	if (t1.substring(i,1) != t2.substring(i,1)) {
    		if(!bool) {
    			cursorposition=i
    			bool=true
    		}
    	}
    }
}

function ValidatePhone(object){

	var p = phonevalue1

	p = p.replace(/[^\d]*/gi,"")

	if (p.length < 3) {
		object.value=p
	} else if(p.length==3){
		pp=p;
		d4=p.indexOf('(')
		d5=p.indexOf(')')
		if(d4==-1){
			pp="("+pp;
		}
		if(d5==-1){
			pp=pp+")";
		}
		object.value = pp;
	} else if(p.length>3 && p.length < 7){
		p ="(" + p;
		l30=p.length;
		p30=p.substring(0,4);
		p30=p30+")"

		p31=p.substring(4,l30);
		pp=p30+p31;

		object.value = pp;

	} else if(p.length >= 7){
		p ="(" + p;
		l30=p.length;
		p30=p.substring(0,4);
		p30=p30+")"

		p31=p.substring(4,l30);
		pp=p30+p31;

		l40 = pp.length;
		p40 = pp.substring(0,8);
		p40 = p40 + "-"

		p41 = pp.substring(8,l40);
		ppp = p40 + p41;

		object.value = ppp.substring(0, maxphonelength);
	}

	GetCursorPosition()

	if(cursorposition >= 0){
		if (cursorposition == 0) {
			cursorposition = 2
		} else if (cursorposition <= 2) {
			cursorposition = cursorposition + 1
		} else if (cursorposition <= 5) {
			cursorposition = cursorposition + 2
		} else if (cursorposition == 6) {
			cursorposition = cursorposition + 2
		} else if (cursorposition == 7) {
			cursorposition = cursorposition + 4
			e1=object.value.indexOf(')')
			e2=object.value.indexOf('-')
			if (e1>-1 && e2>-1){
				if (e2-e1 == 4) {
					cursorposition = cursorposition - 1
				}
			}
		} else if (cursorposition < 11) {
			cursorposition = cursorposition + 3
		} else if (cursorposition == 11) {
			cursorposition = cursorposition + 1
		} else if (cursorposition >= 12) {
			cursorposition = cursorposition
		}

        var txtRange = object.createTextRange();
        txtRange.moveStart( "character", cursorposition);
		txtRange.moveEnd( "character", cursorposition - object.value.length);
        txtRange.select();
    }

}

function ParseChar(sStr, sChar)
{
    if (sChar.length == null)
    {
        zChar = new Array(sChar);
    }
    else zChar = sChar;

    for (i=0; i<zChar.length; i++)
    {
        sNewStr = "";

        var iStart = 0;
        var iEnd = sStr.indexOf(sChar[i]);

        while (iEnd != -1)
        {
            sNewStr += sStr.substring(iStart, iEnd);
            iStart = iEnd + 1;
            iEnd = sStr.indexOf(sChar[i], iStart);
        }
        sNewStr += sStr.substring(sStr.lastIndexOf(sChar[i]) + 1, sStr.length);

        sStr = sNewStr;
    }

    return sNewStr;
}

The format with this code comes out like this: (123)456-7890.

All I need to do is add a space between the closing parenthesis of the area code and the first number of the second set of three digits. I feel like it is a very simple change, but I am stumped. What do I need to change?

… yikes.

That’s a lot of code for a simple masked input field.

function maskPhoneNo() {
  let el = document.getElementById("member_phone");
  let pnum = el.value.replace(/\D*/g,"");
  if (pnum.length >= 3) { pnum = "("+pnum.slice(0,3)+") "+pnum.slice(4); }
  if (pnum.length >= 9) { pnum = pnum.slice(0,9)+"-"+pnum.slice(9); } 
  el.value = pnum;
}
<input type="tel" class="form-control" id="member_phone" name="member_phone" placeholder="(123) 456-7890" maxlength="14" autocomplete="off" onkeyup="maskPhoneNo();" />
1 Like

Using this won’t let me get past the area code. I can type 123 and it will mask the area code to (123), but every character after that is removed when I type it.

Woops, left a typo in.
if (pnum.length >= 3) { pnum = "("+pnum.slice(0,3)+") "+pnum.slice(4); }

should be

if (pnum.length >= 3) { pnum = "("+pnum.slice(0,3)+") "+pnum.slice(3); }

1 Like

It’s anything but simple though I’m afraid… there are a lot of cases to consider, such as accounting for the caret position after inserting a character in the middle of the string, or shifting the remaining characters after pressing del or backspace, copy / pasting etc. In fact, using a 3rd party library would be a valid option here IMHO.

This is true.

How is that not accounted for? If the field contains “(123) 456-7890”, and i press the backspace key on 9, then… the code starts, sees the value of the field as “(123) 456-780” , and parses it the same as if i’d typed another number? I’ll grant you you may want to exclude certain characters from triggering the script (left and right arrows, in particular), but that’s also a 1 liner to add a ‘return’.

It’s always a valid option, but I think it’s overkill personally. YMMV.

It only works if you are to delete a number character though – pressing backspace on e.g. (333) 333-| will leave you after the dash. Anyway all I’m saying is that it is a rather complex topic, which is why I would not consider a 3rd party solution overkill here. But YMMV as well. :-)

If you erase a masking character, then it will replace the masking character, yes.

If my string is (###) ###-#### and i push backspace on the hyphen, yes, it will restore the hyphen - as it should, to conform to the field’s setup. Compliance with the mask is not optional?

Where you might want to tweak the code is to make it check that the length is greater than 9 before adding the hyphen, rather than greater-or-equals, which is fair enough.