Click here to Skip to main content
15,881,715 members
Articles / Web Development / HTML
Tip/Trick

Input Masking in MVC 4 using Data Annotation

Rate me:
Please Sign up or sign in to vote.
4.86/5 (14 votes)
24 Aug 2013CPOL1 min read 149.8K   116   21   22
Input masking in model using data annotation

Introduction

If we want to present dates, phone numbers, etc., you would like them to enter the data in a certain format. You can use easily jquery to mask the input, but the only drawback to this approach is that we need to add those functions for each input to be masked.

In MVC 3/ MVC 4, we can easily achieve this by creating custom data annotation and use it on model.

Background

When I am searching on the Internet, I found nothing which provided Input Masking using data annotation. Only this post provided me with some idea. So, I am working on this and solved the problem.

I am using Masked Input Plugin to mask my input.

Using the Code

First of all, we need to create our own Custom Attribute class.

C#
public class InputMaskAttribute : Attribute, IMetadataAware
  {

   private string _mask = string.Empty;

  public InputMaskAttribute(string mask)
      {
          _mask = mask;
      }

      public string Mask
      {
          get { return _mask; }
      }

      private const string ScriptText = "<script type='text/javascript'>" +
                                        "$(document).ready(function () {{" +
                                        "$('#{0}').mask('{1}');}});</script>";

      public const string templateHint = "_mask";

      private int _count;

      public string Id
      {
          get { return "maskedInput_" + _count; }
      }

      internal HttpContextBase Context
      {
          get { return new HttpContextWrapper(HttpContext.Current); }
      }

      public void OnMetadataCreated(ModelMetadata metadata)
      {
          var list = Context.Items["Scripts"]
          as IList<string> ?? new List<string>();
          _count = list.Count;
          metadata.TemplateHint = templateHint;
          metadata.AdditionalValues[templateHint] = Id;
          list.Add(string.Format(ScriptText, Id, Mask));
          Context.Items["Scripts"] = list;
      }
  }

Here is the screenshot:

Now, we have to create an extension of View Data.

C#
  public static TAttribute GetModelAttribute<TAttribute>
(this ViewDataDictionary viewData, bool inherit = false) where TAttribute : Attribute
        {
            if (viewData == null) throw new ArgumentException("ViewData");
            var containerType = viewData.ModelMetadata.ContainerType;
            return
                ((TAttribute[])
                 containerType.GetProperty(viewData.ModelMetadata.PropertyName).
                 GetCustomAttributes(typeof(TAttribute),
                 inherit)).
                    FirstOrDefault();

        } 

and to call the JavaScript, we will implement a method extension called RenderScripts.

C#
public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
       {
           var scripts = htmlHelper.ViewContext.HttpContext.Items["Scripts"] as IList<string>;
           if (scripts != null)
           {
               var builder = new StringBuilder();
               foreach (var script in scripts)
               {
                   builder.AppendLine(script);
               }
               return new MvcHtmlString(builder.ToString());
           }
           return null;
       }

Now, we have successfully created a custom attribute. Now, create a Model/ViewModel class and use the newly created attribute.

C#
 public class TestModel
{
    [Display(Name = "Date")]
    [InputMask("99/99/9999")]
    public DateTime Date { get; set; }

    [Display(Name = "Phone")]
    [InputMask("(999) 999-9999")]
    public string Phone { get; set; }

    [Display(Name = "Phone + Ext")]
    [InputMask("(999) 999-9999? x99999")]
    public string Phone_Ext { get; set; }

    [Display(Name = "TaxID")]
    [InputMask("99-9999999")]
    public string TaxID { get; set; }

    [Display(Name = "SSN")]
    [InputMask("999-99-9999")]
    public string SSN { get; set; }

    [Display(Name = "ProductKey")]
    [InputMask("a*-999-a999")]
    public string ProductKey { get; set; }

    [Display(Name = "IP")]
    [InputMask("999.999.999.999")]
    public string IP { get; set; }
}

Create a strongly typed view:

C#
<legend>Input Masking</legend>
   <ol>
       <li>@Html.EditorFor(m=> m.Date)
       </li>
          <li>@Html.EditorFor(m=> m.Phone)
       </li>
       <li>@Html.EditorFor(m=> m.Phone_Ext)
       </li>
       <li>@Html.EditorFor(m=> m.TaxID)
       </li>
       <li>@Html.EditorFor(m=> m.SSN)
       </li>
       <li>@Html.EditorFor(m=> m.ProductKey)
       </li>
       <li>@Html.EditorFor(m=> m.IP)
       </li>
   </ol>

In ~/Views/Shared/EditorTemplates, add this:

C#
 @model String

@{ var maskedInput = ViewData.GetModelAttribute<InputMaskAttribute>();
   if (maskedInput != null)
   {
        <div class="editor-label">
            @Html.LabelForModel()
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m, new 
            { id = ViewData.ModelMetadata.AdditionalValues[InputMaskAttribute.templateHint] })
        </div>
   }
} 

You are almost done. Just do one thing, add reference of Masked Input Plugin.

HTML
@section Scripts
   {
       <script src="~/Scripts/InputMask.js"></script>
       @Html.RenderScripts()
   }

Conclusion

Here is the output:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Maxmobility Pvt. Ltd.
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Heriberto Lugo27-Oct-20 17:03
Heriberto Lugo27-Oct-20 17:03 
Questionall images are missing Pin
Mou_kol14-May-18 22:25
Mou_kol14-May-18 22:25 
QuestionNeed some more explanation Pin
Member 84589397-Jul-15 5:19
Member 84589397-Jul-15 5:19 
Questioni cant find the download link in browse code Pin
nymhar7-Jul-15 1:56
nymhar7-Jul-15 1:56 
QuestionWhere do the classes all go? Pin
DevYze5-Jul-15 23:26
DevYze5-Jul-15 23:26 
AnswerRe: Where do the classes all go? Pin
Ankit Sarkar6-Jul-15 16:55
Ankit Sarkar6-Jul-15 16:55 
GeneralRe: Where do the classes all go? Pin
DevYze7-Jul-15 1:40
DevYze7-Jul-15 1:40 
QuestionCan't make this work (MVC 3) Pin
Member 844665017-Jun-14 22:50
Member 844665017-Jun-14 22:50 
I can't get this to work. I followed the article, except that I could not put

XML
@section Scripts
   {
       <script src="~/Scripts/InputMask.js"></script>
       @Html.RenderScripts()
   }


in my page - it broke the page.

Instead I put just

XML
<script src="~/Scripts/InputMask.js"></script>
@Html.RenderScripts()


I annotated the "Amount" property on my model like this

XML
[InputMask("9,999.99")] // used by InputMask.js script
public Decimal? Amount { get; set; }


When I run and the page renders, it then has

XML
<div class="editor-field">
            <input class="text-box single-line" id="NewToken_Amount" name="NewToken.Amount" type="text" value="" />
            <span class="SearchButton"><input type="submit" id="AddToken" value="Add" name="AddToken" class="ui-button ui-widget ui-state-default ui-corner-all"/></span>
            <!-- take out? (we get duplicates with overall error display - is this std for this app?) -->

        </div>


        <script src="~/Scripts/InputMask.js"></script>
        <script type='text/javascript'>$(document).ready(function () {$('#maskedInput_0').mask('9,999.99');});</script>
<script type='text/javascript'>$(document).ready(function () {$('#maskedInput_1').mask('9,999.99');});</script>
<script type='text/javascript'>$(document).ready(function () {$('#maskedInput_2').mask('9,999.99');});</script>



   </fieldset>


I have no idea if that's right, but I am getting no masking in the text box.

Any ideas?
AnswerRe: Can't make this work (MVC 3) Pin
Ankit Sarkar25-Jul-14 20:35
Ankit Sarkar25-Jul-14 20:35 
Questiongood Pin
Member 105104506-Mar-14 18:47
Member 105104506-Mar-14 18:47 
QuestionMade a change to use MVC5 and not using the mask Pin
g.david.carter25-Feb-14 10:06
g.david.carter25-Feb-14 10:06 
AnswerRe: Made a change to use MVC5 and not using the mask Pin
djarvis817-Sep-14 10:10
djarvis817-Sep-14 10:10 
AnswerRe: Made a change to use MVC5 and not using the mask Pin
jdog332111-Nov-15 12:19
jdog332111-Nov-15 12:19 
QuestionPublish on Internet Domain Pin
Member 1040022514-Nov-13 6:26
Member 1040022514-Nov-13 6:26 
QuestionQuestion Pin
Member 1040022513-Nov-13 14:22
Member 1040022513-Nov-13 14:22 
AnswerRe: Question Pin
Ankit Sarkar13-Nov-13 15:18
Ankit Sarkar13-Nov-13 15:18 
AnswerRe: Question Pin
Member 1040022515-Nov-13 8:18
Member 1040022515-Nov-13 8:18 
QuestionWhere can I download . Pin
Member 39187109-Oct-13 2:55
Member 39187109-Oct-13 2:55 
AnswerRe: Where can I download . Pin
Ankit Sarkar9-Oct-13 16:12
Ankit Sarkar9-Oct-13 16:12 
GeneralMy vote of 5 Pin
dgDavidGreene26-Aug-13 11:42
dgDavidGreene26-Aug-13 11:42 
GeneralMy vote of 5 Pin
Anurag Gandhi25-Aug-13 3:18
professionalAnurag Gandhi25-Aug-13 3:18 
GeneralMy vote of 5 Pin
Hasibul Haque24-Aug-13 20:00
professionalHasibul Haque24-Aug-13 20:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.