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);
[...................]
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
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?
Well, you would have to invoke jQuery validate using jQuery (because it's written in jQuery :))
You could add a global event for your inputs, then invoke it on the blurred element. Something like:
$("input").blur(function () {
$(this).valid();
});