MVC 3 Validation - Only show error messages after lost focus or submit?

14,147

Solution 1

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.

Solution 2

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.

Share:
14,147
chief7
Author by

chief7

Solution Architect at a large private enterprise where we build key internal business systems.

Updated on June 04, 2022

Comments

  • chief7
    chief7 about 2 years

    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" />
    }