Creating Customized Validation TextBoxes with dojox.validate

I recently came across the need to make a validation textbox that validated US phone numbers. I know there are some JavaScript regular expressions that attempt to validate a phone number - this being the closest one I found to my needs: https://snippets.dzone.com/posts/show/597

There were things about this I didn’t like though such as always allowing a 7-digit phone number and not allowing them to enter area codes without parens like: 123-456-7890.

I grepped for “phone” in the dojo source and saw what looked like a great solution in the often forgotten but still useful dojox.validate package, specifically dojox.validate.us.isPhoneNumber. Those were the patterns I was looking for (I’ll get to 7-digit numbers in a sec). But how could I use this with a validation textbox which has a RegExp and RegExpGen param that are looking for javascript regular expressions whereas isPhoneNumber was using a number formatter to determine if it passed validation?

Seemed like my only answer was to create my own dijit which I called dojoc.form.PhoneTextBox. Thankfully the code for this guy is really pretty basic, all I had to do was create a basic stub for my custom digit and override the validator method:

dojo.provide("dojoc.form.PhoneTextBox");
 
/* Create an extension of new dijit.form.ValidationTextBox to validate US phone numbers,
   borrow the validation routine from dojox.validate */
 
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dojox.validate.us");
 
dojo.declare(
   "dojoc.form.PhoneTextBox",
   [dijit.form.ValidationTextBox], {
      validator: function(/*anything*/value, /*dijit.form.ValidationTextBox.__Constraints*/constraints){
         // summary: user replaceable function used to validate the text input against the regular expression.
         return dojox.validate.us.isPhoneNumber(value) &&
                 (!this.required || !this._isEmpty(value)) &&
                 (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
      }
   }
);

This works exactly like a ValidationTextBox except that it would ignore the regExp and regExpGen params if they were used. The nice thing here is that if another validator looks useful in dojox.validate, it’s pretty easy to make another one of these. dojox.validate has pattern matching utilities for things like Social Security numbers, credit card numbers, ISBN’s, zipcodes and more. The same pattern above can be applied to leverage this tested functionality in your validation textbox instead of trying to come up with your own value for a ValidationTextbox’s regExp param.

Anyway, there really isn’t too much going on in the code above other than standard custom digit boilerplate except my validator function. I copied that from ValidationTextBox and updated the boolean expression, replacing the first regular expression validation condition with a call to dojox.validate.us.isPhoneNumber(value) - the other conditions following I left alone. Now I have a nice validation text box for my phone numbers.

I decided to take this a step further and allow the user to pass an additional param: requiresAreaCode which would default to true, but setting to false I want to allow some 7 digit patterns to pass. In order to do this, I created a copy of dojox.validate.us.isPhoneNumber and added the additional number formats I wanted to allow users to have to enter phone numbers without area codes. Here is the complete digit (note the boolean logic had to be updated in the validator function to check my new param):

dojo.provide("dojoc.form.PhoneTextBox");
 
/* Create an extension of new dijit.form.ValidationTextBox to validate US phone numbers,
   borrow the validation routine from dojox.validate */
 
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dojox.validate.us");
 
dojox.validate.us.isPhoneNumberAreaCodeOptional = function(/*String*/value){
   // summary: Validates 7 or 10 US digit phone number for several common formats
   // value: The telephone number string
 
   var flags = {
      format: [
         "###-###-####",
         "(###) ###-####",
         "(###) ### ####",
         "###.###.####",
         "###/###-####",
         "### ### ####",
         "###-###-#### x#???",
         "(###) ###-#### x#???",
         "(###) ### #### x#???",
         "###.###.#### x#???",
         "###/###-#### x#???",
         "### ### #### x#???",
         "##########",
         "###-####", // added these additional formats for numbers w/o area codes
         "### ####",
         "###-#### x#???",
         "### #### x#???",
         "#######"
      ]
   };
   return dojox.validate.isNumberFormat(value, flags); // Boolean
}
 
dojo.declare(
   "dojoc.form.PhoneTextBox",
   [dijit.form.ValidationTextBox], {
      requiresAreaCode: true,
 
      validator: function(/*anything*/value, /*dijit.form.ValidationTextBox.__Constraints*/constraints){
         // summary: user replaceable function used to validate the text input against the regular expression.
         return ((this.requiresAreaCode && dojox.validate.us.isPhoneNumber(value)) ||
                 (! this.requiresAreaCode && dojox.validate.us.isPhoneNumberAreaCodeOptional(value))) &&
            (!this.required || !this._isEmpty(value)) &&
            (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
      }
   }
);