3

I have setup the entities in my MVC 3 app with DataAnnotations (required, stringlength, etc) and the MVC page is showing validation error messages appropriately. But, the error messages are shown as soon as the page loads on a new form before the user has had the chance to enter an invalid value.

I had used JQuery validation a few years ago and was able to only show the error messages after the user lost focus on a field or attempted to submit the form. In fact, I think it was the default behavior.

Is there anyway to do the same in MVC 3 using DataAnnotations?

EDIT: Here is the HTML

<div class="form horizontal floated w50p">
<h3>Billing Information</h3>
@using(Html.BeginForm()){
    <div class="item">
        <div class="label">
            <label>* First Name</label></div>
        <div class="value">@Html.TextBoxFor(x => x.Name)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.Name)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>* Address 1</label></div>
        <div class="value">@Html.TextBoxFor(x => x.Street1)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.Street1)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>Address 2</label></div>
        <div class="value">@Html.TextBoxFor(x => x.Street2)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>Address 3</label></div>
        <div class="value">@Html.TextBoxFor(x => x.Street3)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>City</label></div>
        <div class="value">@Html.TextBoxFor(x => x.City)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.City)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>State/Province/Region</label></div>
        <div class="value">@Html.TextBoxFor(x => x.StateProv)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.StateProv)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>Zip / Postal Code</label></div>
        <div class="value">@Html.TextBoxFor(x => x.PostalCode)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.PostalCode)</div>
    </div>
    <div class="item">
        <div class="label">
            <label>* Contact Phone</label></div>
        <div class="value">@Html.TextBoxFor(x => x.ContactPhone)</div>
        <div class="value">@Html.ValidationMessageFor(x => x.ContactPhone)</div>
    </div>        <input type="submit" value="Submit" />
}
chief7
  • 14,263
  • 14
  • 47
  • 80

2 Answers2

4

The default behavior is exactly what you describe (errors should appear only after a field loses focus or form is submitted). So, there must be something wrong with your view or controller. Specifically, it sounds like the validator thinks the user is posting back even on the first view of the form. The first view of the form should be a GET not a POST. If you paste your controller code, that might help us diagnose it better.

devuxer
  • 41,681
  • 47
  • 180
  • 292
  • I'm currently using the same action for gets and posts. Can you give an example of how the validator could get confused? – chief7 May 19 '11 at 01:57
  • I double checked and the RequestType is a "GET" in the controller action when page first loads. Then a "POST" when the form is valid and submitted. – chief7 May 19 '11 at 10:14
3

You mean like enabling client validation? Sure, that's easy. Just:

  1. create a view model
  2. decorate it
  3. create controller
  4. create a view
  5. include proper jquery scripts

So let's go ahead and follow those steps.

View model:

public class ProductViewModel
{
    [Required] // <-- you could use any data annotation attributes you like
    public string Name { get; set; }
}

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new ProductViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(ProductViewModel model)
    {
        return View(model);
    }
}

View:

@model ProductViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.Name)
    @Html.EditorFor(x => x.Name)
    @Html.ValidationMessageFor(x => x.Name)
    <input type="search" value="OK" />
}

Now leave the field blank and client validation will trigger assuming it is enabled in web.config (which it is by default when you create a new ASP.NET MVC 3 project using the default Visual Studio template):

<appSettings>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

If you want to handle custom validation attributes you could but it might be a little more painful. And once you get yourself confronted to real world applications and realize the weaknesses of declarative validation using attributes (data annotations) I would strongly recommend you checking out FluentValidation.NET.

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I am currently using data annotations to decorate my models for client/server side validation. I haven't run into any problems worth mentioning, but since I'm just starting out on an MVC app, I am interested in what you find to be weak in regards to data annotations vs the FluentValidation.NET that you mentioned. – Jed May 19 '11 at 12:23
  • @Jed, let's take the following very common case: imagine you have some form containing a checkbox. Based on whether the checkbox is selected you need to ensure that some other properties on the model are required. If the checkbox is not checked those properties should not be required. Doing this with declarative data annotation attributes seems a bit ugly. – Darin Dimitrov May 19 '11 at 13:50
  • @Jed - wouldn't the IValidatableObject work better for that scenario instead of DataAnnotation attributes? – chief7 May 19 '11 at 17:11
  • @chief7 - Which scenario are you referring to? – Jed May 19 '11 at 20:05