Validating Hidden Fields in ASP.NET MVC 2

One of the many nice things they have added in MVC 2 is model/view model validation on both the client and server side.  I won’t go into the basics here since they have been covered extensively by others.  However, recently I was adding validation to require a value for a hidden field on a form, and found that the default validation functionality just didn’t work on the client side for a hidden field.  Here I will go over how I added some custom validation to allow me to do it.

While it might sound weird to validate a hidden field, something a user will never directly interact with, in this age of complex interfaces built in JavaScript it’s easy to imagine a scenario where a series of interactions leads to storing some kind of value in a hidden field.  If that end value is something that is required, it’s only natural that that should be enforced by the model.

First, let’s start by defining a very simple view model for the form:

public class DemoForm
{
    [Required(ErrorMessage = "You must enter a name")]
    public string Name { get; set; }
}

It just defines a single property for storing a name.  Now we can define a very basic view that is strictly typed to that view model.  Here is the code for setting up the form:

<% using (Html.BeginForm())
{ %>

    <%= Html.HiddenFor(model => model.Name) %>

    <p>
        <%= Html.ValidationMessageFor(model => model.Name) %>
    </p>

    <input type="submit" value="Submit" />

<% } %>

For the sake of this demo, I am going to add some buttons that can populate and clear the hidden field.  To get that out of the way, here is the markup for that:

<div>
    <input id="PopulateField" type="button" value="Populate Hidden Field" />

    <input id="ClearField" type="button" value="Clear Hidden Field" />
</div>

<p>
    Last submitted value: <%= ViewData["Name"] %>
</p>

and here is some JavaScript (using jQuery) to wire them up:

And now we’re almost done with the boring part.  Finally, we wire up the controller actions like so:

[HttpGet]
public ActionResult Index()
{
    return View();
}

[HttpPost]
public ActionResult Index(DemoForm form)
{
    ViewData["Name"] = form.Name;
    return View(form);
}

Validation form

If you run the page now, you will get correct server-side validation, but nothing on the client.  To get client validation in MVC, we need to tell the page to enable client validation.  To do that, call this before starting the form:

<% Html.EnableClientValidation(); %>

You will also need some JavaScript references to these files, which are included by default in any new MVC project:

<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/MicrosoftAjax.js") %>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/MicrosoftMvcAjax.js") %>"></script>
<script type="text/javascript" src="<%= ResolveUrl("~/Scripts/MicrosoftMvcValidation.js") %>"></script>

Now if you reload the page, client validation still isn’t working.  Why not?  After digging through the Microsoft validation scripts a bit, I found that the Required validator ignores hidden fields altogether in JavaScript.  We could change it from being a hidden field to a text field and the same code would work as expected, but that’s not what we want to do.

As it turns out, they made it rather simple to extend the built-in validation with your own custom rules.  First, we’ll define the attribute class, so that it can be added as a decorator to a property the same way the other validators work.  In this case, since the Required attribute actually works fine on the server side, our class will extend that and do nothing else.  This way we can provide the client side functionality and rely on the existing server validation.

public class HiddenRequiredAttribute : RequiredAttribute
{
}

Now that we have the attribute, we need a validator that uses it.  To do that, we extend the DataAnnotationsModelValidator class, and tell it to use the attribute we just defined:

public class HiddenRequiredValidator : DataAnnotationsModelValidator<HiddenRequiredAttribute>
{
    private string _errorMessage;

    public HiddenRequiredValidator(ModelMetadata metaData, ControllerContext context, HiddenRequiredAttribute attribute)
        : base(metaData, context, attribute)
    {
        _errorMessage = attribute.ErrorMessage;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = _errorMessage,
            ValidationType = "hiddenRequired"
        };

        return new[] { rule };
    }
}

The important part to notice here is where we set the ValidationType to “hiddenRequired.”  This is the unique identifier we define for referencing our validator in JavaScript.  Remember it, because you’re going to need it later.

So now we have an attribute, and a validator for it.  Next up, we need to register our validator in the application’s Application_Start function:

DataAnnotationsModelValidatorProvider
    .RegisterAdapter(typeof(HiddenRequiredAttribute), typeof(HiddenRequiredValidator));

Now let’s switch the view model’s Name property to use the new HiddenRequired attribute instead of the Required one we had before:

public class DemoForm
{
    [HiddenRequired(ErrorMessage = "You must enter a name")]
    public string Name { get; set; }
}

All that remains is to put in some JavaScript code to handle the validation.  I’ll show the code here, and then discuss it.  Since this is a contained demo, I will add the code directly to the view.

Sys.Mvc.ValidatorRegistry.validators["hiddenRequired"] = function(rule)
{
    return function(value, context)
    {
        if (value)
        {
            return true;
        }

        return rule.ErrorMessage;
    }
};

If that code looks simple, that’s because it is.  Since we’re only validating that the field has some kind of value, that is all we need to check for.  The reason that the return function is wrapped in another function is to allow for adding more complex logic before the return function if needed.  For this example, it isn’t needed.

Validation form

Now if you reload the page you will get the client-side validation we were aiming for, triggered by the submit button.  Always remember that client-side validation is just there for improving the user experience, and is no substitute for server validation.

Here’s the demo project used in this post if you want to see it in action.

Tags: , ,

6 Responses to “Validating Hidden Fields in ASP.NET MVC 2”

  1. Hi,

    I am not able to go to the demo project download link.
    Please do the needful.
    Link is giving 404 error.

  2. Thanks for the heads up, should be fixed now!

  3. Hi, thanks for your article – I was looking for just this. However, once I got to the end and started to think about where it’s more appropriate to place the actual validation function, I started spilunking through the MicrosoftMvcValidation.js and realized that none of this is really necessary. I believe, all you have to do is alter the Sys.Mvc.RequiredValidator._isTextualInputElement() function and add the “HIDDEN” inputType case. Wouldn’t this be enough and easier/simpler than creating new attributes and so on?

  4. @Kon: Glad you found the article useful. I had thought about doing it that way, but that didn’t feel right since it meant changing their implementation for _isTextualInputElement(), which could cause problems if they change that function otherwise in future versions. It doesn’t seem worth it to change their implementation when they already provide the means to add your own custom behavior.

    On top of that, I also figured this provided a good example of how to add custom validation in general :)

  5. silent sojourner

    Actually only ie 7 has this issue. ie 8 can validate hidden fields even without your added code.

  6. how to validate using hidden field values on submit of a form.

Leave a Reply