Using ASP.NET MVC 3 and jquery, we can easily and automatically validate and format data such as phone numbers and social security numbers into user friendly formats like (xxx) xxx-xxxx or xxx-xx-xxxx, not only when data is presented to the user, but also while the user is typing in data! We can also block the user from even entering non-numeric characters if we wish. We can parse that data after a form submit and strip out the parentheses and dashes before it reaches the controller action. We can also easily control the appearance of the input textboxes of all the fields in all the forms in one easily modified location. What’s nice about the approach presented here is that the developer only needs to designate a model field as a social security or phone number in one location (the view model) and the system handles all the html, jquery, and data cleanup automagically. This is done without using the class html attribute on any of the input controls, which frees the developer to use css classes as normal. Furthermore, this approach is compatible with Microsoft’s jquery unobtrusive client-side validation, so you can present the user with friendly highlighting and popups before invalid data is even sent to the server. Put together, these techniques create a crisp, fluid experience for the users and a fast, easy development environment for the developers.

Jquery.maskedinput is a great tool for formatting user inputs, however the input masking not only changes the data the user sees but also changes the data posted to the controller action from the automatic model binding during the form submit. If the database field requires all numeric characters or dashes instead of parenthesis, you’ve got a mess to clean up. Furthermore, manually attaching masks to every field in every view is pretty tedious. This is where ASP.NET MVC really comes to the rescue with custom model binders and Editor Templates to automatically handle all that formatting, masking and unmasking for you. While there are certainly a lot of ways you can skin the cat with jquery and ASP.NET MVC, this article has some examples that work extremely well together using the latest technologies.

The examples here use jquery 1.4.4, jquery.UI 1.8.9, jquery.maskedinput 1.2.2 and ASP.NET MVC 3. You can find jquery and jquery.UI on the jquery.com site, and jquery.maskedinput.js on the plugins.jquery.com website. Be sure to add a content reference in your master page to your js files in your project.

Attribute tags for our model fields

We need a way of telling the custom model binder (which we will create later) that a model field is a social security number or phone number, and the way we’re going to do this is with a couple of stubbed out custom Attributes. These attribute tags are just empty raw Attributes now, but can be embellished with validation or other tricks later.

We’ll want to easily add style tags and other html attributes to form fields. Html attributes are passed to the Editor Template as key values in the Editor Template’s ViewData. We can create this ViewData extension method that lets us easily add style segments to the Editor Templates ViewData html attributes by appending a style segments to the “style” string in ViewData.

Editor Templates

Editor Templates conveniently give you a great deal of power by allowing you to automatically format all datatypes the way you like without having to clutter up your view pages. In our example we have phone numbers and social security numbers that are both strings in our model, but need to be formatted differently. A simple way of doing this is to override the String.ascx Editor Template and use a switch to change the formatting for the social security and phone numbers. We use this Editor Template to add a jquery.maskedinput on each of the input boxes that block the users from adding anything other than numeric characters and puts their inputs into our preferred formats as they type.

In your Views folder, under the Shared folder, create an EditorTemplates folder if you don’t already have one, and add a “MVC View User Control (ASPX)” control named String.ascx (yes, Visual Studio 2010 says it’s an ASPX when it’s actually an ascx).

Notice in the example below that the view control’s ViewData is passed directly to the htmlAttributes object in the Html.TextBox. Our AddStyle ViewData extension uses that feature to format the input boxes with our own style tags such as width. Your String.ascx will look something like this:

In MVC’s convention over configuration scheme, the ASP.NET MVC engine will automatically use the String.ascx to produce any model field of the string datatype when a view calls EditorFor. In your view, you just type <%: Html.EditorFor(x => x.SSN) %> and MVC will handle the rest.

ALTERNATIVE: Instead of lumping all the model types into the String.ascx, you could create a separate Editor Template for SocialSecurityNumber.ascx and PhoneNumber.ascx, but then you’d have to call EditorFor(x=>x.SSN, “SocialSecurityNumber”) instead of just EditorFor(x=>x.SSN). I prefer to lump them all in the String.ascx because the developers only have to set the type in one place (the model field) instead of in both the views and the view models. There’s probably a little bit of a performance hit with the lump String.ascx architecture because of the switch in the String.ascx, so race car sites may want to go with the split Editor Template alternative.

Custom Model Binder

Finally, we need to take the user’s input coming from the form fields on its way to the controller action during a form submit and strip the masking characters, returning it to a state the rest of our code is expecting. Specifically for our example, we want to take social security numbers and phone numbers and strip out the parentheses and dashes we added on the form. This is easy to do with a custom model binder that overrides ASP.NET MVC’s default model binder which controls how form fields are automagically mapped to the view model posted to a controller action during a form submit here:

[HttpPost]public ActionResult MyAction(MyModel viewModel)

In our custom model binder we want to override the DefaultModelBinder’s SetProperty method and find all strings that are tagged with our social security or phone number attribute tags. Then we use regex to strip out anything that is not a numeric field. We’ll also take this opportunity to clean up the user inputs by removing any whitespace padding. It doesn’t get much simpler than this:

9 Comments:

Hello, I tried to impliment your solution, but ran into problems. The idea sounds wonderful tying in editmasks to the model but I cannot get it to work. I am hoping that you could post a small app that uses a phone number mask so that I could get this to work. It would be greatly appreciated. Thanks for the article.

I downloaded your sample and it runs as your post says it should. I copied over all the bits and pieces, decorated my model and ran my project. When I view a page with a phone input the mask does *NOT* activate. When I inspect the element I can see that the JS was correctly written and references the correct input box – but no mask.

Question – if I *want* to save the phone with its mask I should just format it myself in the back end? I am using GData to store my contacts and would like to see it formatted uniformly when I open my Google Contacts directly.

One problem with the attributes that I wonder if you have already solved. I’m using Database First, where the MS Entity Framework generates the data model classes as *.tt files, so I’m using meta data classes to hold the validators and other attributes (Required, DisplayName, etc).

I assumed these metadata classes would also hold the custom attributes that you suggest in this article (eg SocialSecurityNumber,PhoneNumber).

Unfortunately your GetModelAttribute method does not see the attributes when they are on the metadata classes. The call to GetCustomAttributes comes back empty. If I add the attributes directly to the data model class generated by the Entity Framework (the *.tt class) your method works perfectly, but of course it is bad practice to mark up the *.tt classes, since they are overwritten when the model is updated.

A workaround is the performance optimization that you suggest (creating separate SocialSecurityNumber and PhoneNumber templates and calling them by name). But I’m wondering, is there a way to read the attributes from the meta data classes in a method like your GetModelAttribute extension?

Whenever I generate the models from the database, I copy the classes out so I have more control over them, so I can add the model attributes, etc. That would definitely work for you, but it may not have the convenience you’re looking for. You can try posting the question on StackOverflow.com and see if anyone has some good ideas.