83 lines
5.5 KiB
Markdown
83 lines
5.5 KiB
Markdown
---
|
||
title: "jQuery Validate and Jeditable, Part 1"
|
||
date: 2009-12-31T21:32:00-06:00
|
||
slug: jquery-validate-and-jeditable-part-1
|
||
published: true
|
||
---
|
||
|
||
I was recently tasked to add server-and-client-side form validation for an ASP.NET MVC site - which already uses in-place editing courtesy [Jeditable](http://www.appelsiini.net/projects/jeditable). I really like the field editing experience that Jeditable provides – it makes form entry in the browser interactive, is fairly straightforward to integrate, and it’s adaptable to many scenarios. It does not, however, have any validation mechanism built in.
|
||
|
||
Our project already used [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) for a few forms by using the HTML class definitions – like adding class=”required phone” to an INPUT element. This works great, but doesn’t provide any server-side validation tie-in.
|
||
|
||
Earlier this year, I remembered having seen a [presentation](http://speakerrate.com/talks/1218-useful-jquery-tips-tricks-and-plugins-with-asp-net-mvc) by [Elijah Manor](http://elijahmanor.com/) who mentioned using [xVal](http://xval.codeplex.com/) for robust server and client side validation. And with the news that [MVC 2 will have a built in validation technique similar to xVal](http://haacked.com/archive/2009/10/01/asp.net-mvc-preview-2-released.aspx), it was an easy decision to start investigating this library.
|
||
|
||
[xVal](http://xval.codeplex.com/) is a pretty easy to get integrated. The first step is to decorate the model with validation rules – I’ve decided to use .NET framework’s [DataAnnotations](http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx), which ends up looking like:public class ValidateViewModel
|
||
{
|
||
[Required(ErrorMessage = "This string is required")]
|
||
public string StringRequired { get; set; }
|
||
|
||
[Range(13, 100, ErrorMessage = "Must be between 13 and 100")]
|
||
public double DoubleRange13_100 { get; set; }
|
||
}public class ValidatedController
|
||
{
|
||
public ViewResult Index()
|
||
{
|
||
return View(new ValidateViewModel());
|
||
}
|
||
}<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<ValidateViewModel>" %>
|
||
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
|
||
<% using(Html.BeginForm()) {%>
|
||
<%= Html.ValidationSummary() %>
|
||
<label for="StringRequired">String Required:</label>
|
||
<%= Html.TextBoxFor(m => m.StringRequired) %>
|
||
<%= Html.ValidationMessageFor(m => m.StringRequired)%>
|
||
|
||
<label for="DoubleRange13_100">Doulbe between 13 and 100:</label>
|
||
<%= Html.TextBoxFor(m => m.DoubleRange13_100) %>
|
||
<%= Html.ValidationMessageFor(m => m.DoubleRange13_100)%>
|
||
<%} %>
|
||
</asp:Content>
|
||
|
||
To validate this ViewModel server side, we use a [DataAnnotationsValidationRunner](http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/) like the one in xVal’s documentation:[AcceptVerbs(HttpVerbs.Post)]
|
||
public ActionResult Update(ValidateViewModel model)
|
||
{
|
||
try {
|
||
DataAnnotationsValidationRunner.ValidateModel(model);
|
||
// it’s valid, do the actual update
|
||
var domainObject = ValidateDomainModel.Find(model.id);
|
||
Map(model, domainObject);
|
||
domainObject.Update();
|
||
}
|
||
catch(RulesException ex) {
|
||
ex.AddModelStateErrors(ModelState, null);
|
||
}
|
||
|
||
return ModelState.IsValid ? RedirectToAction("Completed")
|
||
: (ActionResult) View();
|
||
}public static class DataAnnotationsValidationRunner
|
||
{
|
||
private static IEnumerable<ErrorInfo> GetErrors(object instance)
|
||
{
|
||
return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
|
||
from attribute in prop.Attributes.OfType<ValidationAttribute>()
|
||
where !attribute.IsValid(prop.GetValue(instance))
|
||
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(String.Empty), instance);
|
||
}
|
||
|
||
/// <summary>Validates the given <param name="model">model</param></summary>
|
||
/// <exception cref="RulesException">Thrown if any errors are found</exception>
|
||
public static void ValidateModel(object model)
|
||
{
|
||
var errors = GetErrors(model);
|
||
if (errors.Any())
|
||
throw new RulesException(errors);
|
||
}
|
||
}
|
||
|
||
*Aside: the project uses the *[*Active record pattern*](http://en.wikipedia.org/wiki/Active_record_pattern)* via *[*Castle ActiveRecord*](http://www.castleproject.org/activerecord/index.html)* for data access without an intermediate business-logic layer. For this case, the rules are defined on the ViewModel and are validated in the controller. This does add some noise in the actions – I’m definitely interested in other methods for handling this. Such as - perhaps the validation could be placed inside the ViewModel?*
|
||
|
||
The next step is to add client-side validation. [xVal](http://xval.codeplex.com/)’s built-in [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) rule generator makes this ridiculously simple – just reference jquery.validate.js and xVal.jquery.validate.js in the view, and then this single line:<%= Html.ClientSideValidation<ValidateViewModel>() %>
|
||
|
||
The rules defined in the ViewModel will now be validated client side and enforced for server side actions. This works great for a statically defined HTML form, but I learned that integrating with [Jeditable](http://www.appelsiini.net/projects/jeditable)’s dynamic inline forms to be not so straight forward.
|
||
|
||
Continued in [Part 2](/2010/01/03/jQueryValidateAndJeditablePart2.aspx)… |