Search code examples
c#asp.net-mvcvalidationasp.net-mvc-4client-side-validation

Performing client-side validation in MVC4 View against ViewModel


I would like to know what is the best approach to handle client-side, javascript or jQuery driven validation of MVC4 fields against attributes placed on a ViewModel's fields.

First, let's pick the example. A login creation screen for Administrators shown the first time the application starts (just not to say to the site owner "use admin/admin as login the first time").

ViewModel:

public class AdministratorViewModel : AbstractViewModel
{
    [Required]
    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblUsername")]
    public string Username { get; set; }

    [Required]
    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblEmailAddress")]
    [EmailAddress]
    public string EmailAddress { get; set; }

    [Required]
    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPassword")]
    [AdminPassword]
    public string Password { get; set; }

    [Required]
    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPasswordConfirm")]
    [Compare("Password")]
    public string PasswordConfirm { get; set; }

    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblLastLogin")]
    public DateTime? LastLogin { get; set; }

    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPasswordExpiry")]
    public DateTime? PasswordExpiry { get; set; }

    [Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblBlocked")]
    public bool Blocked { get; set; }
}

Partial view (only a few fields needed when creating the first admin)

@using (Html.BeginForm())
{
    @Html.ValidationSummary(false)
    @Html.AntiForgeryToken()

    <fieldset>
        <legend>@ManageAdminsViewResources.legendCreateAdmin</legend>

        <div class="desktoptile">
            @Html.LabelFor(m=>m.Username)
            @Html.EditorFor(m => m.Username)
            @Html.ValidationMessageFor(m => m.Username)
        </div>

        <div class="desktoptile">
            @Html.LabelFor(m=>m.Password)
            @Html.PasswordFor(m => m.Password)
            @Html.ValidationMessageFor(m => m.Password)
        </div>

        <div class="desktoptile">
            @Html.LabelFor(m=>m.PasswordConfirm)
            @Html.PasswordFor(m => m.PasswordConfirm)
            @Html.ValidationMessageFor(m => m.PasswordConfirm)
        </div>

        <div class="desktoptile">
            @Html.LabelFor(m=>m.EmailAddress)
            @Html.EditorFor(m => m.EmailAddress)
            @Html.ValidationMessageFor(m => m.EmailAddress)
        </div>

        <input type="submit" value="@ManageAdminsViewResources.btnCreate"/>
    </fieldset>
}

Controller

    [AllowAnonymous]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult CreateFirst(AdministratorViewModel viewModel)
    {
        if (!ModelState.IsValid) return View(viewModel);
        [...................]

Currently

If I enter an invalid email address, an empty password, etc. in the form and hit Submit I'm correctly notified of the errors. Ok, let's go on

What I want

Since I'm doing a Metro-stylish design, I would like that every time the user unfocuses a text box validation for that field occurs.

Writing hard-coded jQuery fragments is not the best option. I would like a data-driven approach, possibly embedded in MVC4 which I'm currently learning.

So, given a ViewModel with standard and custom attributes (for which, no matter what, a little Javascript is required, think about the Org.Zighinetto.AdminPasswordAttribute that checks password complexity), how do I enforce client-side validation the most unobtrusive way, without specifying client-side tags on each and every html tag and writing the least possible amount of code?

Is still there any secret in ASP.NET MVC 4 validation that I have to unhide?


Solution

  • From my (learning) point of view, the correct answer should be:

    Explanation:

    Validation of common attributes is done by MVC4 automatically when jQuery Unobtrustive Validator is loaded into the page, otherwise only server-side validation is performed.

    Most, if not all of MVC4 ValidationAttributes implement IClientValidation. This interface wraps jQuery Validator validation functions in server-side code. It's hard to explain how exactly it works, but saying that this interface returns the name of the client-side function (either provided by jQuery distribution or implemented by user), while basically wrong at least gives the idea to a novice user trying to understand how validation works.

    Answer:

    Continue using data-driven model/viewmodel annotations. Check if NuGet package jQuery Unobtrusive Validation is loaded in the page, then implement IClientValidation as needed (I found a tutorial here about multiple errors), fields are validated automatically.