162 lines
7.2 KiB
Markdown
162 lines
7.2 KiB
Markdown
---
|
||
title: "jQuery Validate and Jeditable, Part 2"
|
||
date: 2010-01-02T23:47:00-06:00
|
||
slug: jquery-validate-and-jeditable-part-2
|
||
published: true
|
||
---
|
||
|
||
When using [Jeditable](http://www.appelsiini.net/projects/jeditable), there is no form element to bind [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) rules with. Instead, when an editable element is clicked or activated, it dynamically creates a new form and input element and destroys them after the user is done editing. For the ViewModel from [Part 1](/2010/01/01/jQueryValidateAndJeditablePart1.aspx), the View might be rendered like so for [Jeditable](http://www.appelsiini.net/projects/jeditable):
|
||
|
||
```
|
||
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<ValidateViewModel>" %>
|
||
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
|
||
<% using(Html.BeginForm()) {%>
|
||
<%= Html.ValidationSummary() %>
|
||
<label for="StringRequired">StringRequired:</label>
|
||
<div class="editable" id="StringRequired" name="StringRequired">
|
||
<%= Model.StringRequired %>
|
||
</div>
|
||
|
||
<label for="DoubleRange13_100">DoulbeRange13_100:</label>
|
||
<div class="editable" id="DoubleRange13_100" name="DoubleRange13_100">
|
||
<%= Model.DoubleRange13_100%>
|
||
</div>
|
||
<%} %>
|
||
</asp:Content>
|
||
```
|
||
|
||
[xVal](http://xval.codeplex.com/)’s `ClientSideValidation<TViewModel>()` used in [Part 1](/2010/01/01/jQueryValidateAndJeditablePart1.aspx) won’t work to validate this. The reason? It generates a script that binds validation directly to the form elements on page load. The rendered script looks for the ViewModel looks like:
|
||
|
||
```
|
||
<script type="text/javascript">
|
||
xVal.AttachValidator(null,
|
||
{"Fields":[
|
||
{
|
||
"FieldName":"StringRequired",
|
||
"FieldRules":[
|
||
{
|
||
"RuleName":"Required",
|
||
"RuleParameters":{
|
||
|
||
},
|
||
"Message":"This string is required"
|
||
},
|
||
{
|
||
"FieldName":"DoubleRange13_100",
|
||
"FieldRules":[
|
||
{
|
||
"RuleName":"Range",
|
||
"RuleParameters":{
|
||
"Min":"13",
|
||
"Max":"100",
|
||
"Type":"decimal"
|
||
},
|
||
"Message":"Must be between 13 and 100"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]}, {})
|
||
</script>
|
||
```
|
||
|
||
The rules are in the xVal’s StandardJSON format and the `AttachValidator` function (in `xVal.jquery.validate.js`) scans the DOM and attaches [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) rules as attributes to the matched input elements. Since [Jeditable](http://www.appelsiini.net/projects/jeditable) doesn’t create these elements until they’re actively being edited, the rules have nothing to attach to since they don’t exist yet. Fortunately, [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) provides several strategies for defining the rules. In addition to being able to attach attributes to the input elements, the rules can be placed in a separate data structure. [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) refers to these as “static rules”. Instead of attaching the xVal rule set directly to the elements, it can be adapted to the static rule set that [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) can use directly. The structure for the ViewModel rules will look like:
|
||
|
||
```
|
||
{
|
||
rules: {
|
||
StringRequired: {
|
||
required: true
|
||
},
|
||
DoubleRange13_100: {
|
||
number: true,
|
||
range: ["13”, "100"]
|
||
}
|
||
}
|
||
messages: {
|
||
StringRequired: {
|
||
required: "This string is required."
|
||
},
|
||
DoubleRange13_100: {
|
||
range: "Must be between 13 and 100"
|
||
}
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
I've adapted some javascript to do this conversion - it's available [here](../media/images/jQueryValidateandJeditable_E71E/xValRuleAdapter.js). To get the ViewModel’s rules into this format for javascript consumption, this line is added:
|
||
|
||
```
|
||
<script type="text/javascript">
|
||
var validateOptions
|
||
= convertXvalToValidateOptions(
|
||
<%= Html.ClientSideValidationRules<ValidateViewModel>()%>
|
||
);
|
||
</script>
|
||
|
||
```
|
||
|
||
|
||
|
||
To get these attached to form elements as soon as the user activates them, [Jeditable](http://www.appelsiini.net/projects/jeditable)’s “plugin” feature is utilized:
|
||
|
||
```
|
||
$(function() { // <- on document ready
|
||
// register plugin with Jeditable to tie in jQuery Validate
|
||
$.editable.types['text'].plugin = bindValidate;
|
||
|
||
// attach Jeditable to each element with class "editable"
|
||
// Note: this must be done one-by-one so that the
|
||
// element's name can be assigned to Jeditable's "name"
|
||
// option which is used by jQuery Validate
|
||
$('.editable').each(function() {
|
||
var element = $(this);
|
||
|
||
element.editable(
|
||
'SaveUrlOrFunctionGoesHere',
|
||
{
|
||
// submit when the element is blurred
|
||
onblur: 'submit',
|
||
onsubmit: jeditableValidate,
|
||
// assign the name of the input element
|
||
// from the element's name - this is needed
|
||
// because it's what jQuery Validate uses
|
||
// to bind the rules to the input element
|
||
name: element.attr('name')
|
||
}
|
||
);
|
||
});
|
||
});
|
||
|
||
// Jeditable plugin
|
||
function bindValidate(settings, self) {
|
||
// attach jQuery Validate to
|
||
// Jeditable's dynamically created form
|
||
$('form', self).validate(validateOptions);
|
||
}
|
||
|
||
// runs before values are submitted to server
|
||
function jeditableValidate(settings, self) {
|
||
// validate the Jeditable dynamically created form
|
||
return $('form', self).valid();
|
||
}
|
||
|
||
```
|
||
|
||
With this glue in place, the form elements will now be validated with the rules defined in the ViewModel. All fields valid:
|
||
|
||
[](../media/images/jQueryValidateandJeditable_E71E/jQueryValidateJeditable1.png)
|
||
|
||
…and here after both have invalid values:
|
||
|
||
[](../media/images/jQueryValidateandJeditable_E71E/jQueryValidateJeditable2.png)
|
||
|
||
A few notes:
|
||
|
||
- Any additional options to be sent to [jQuery Validate](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) can be attached to the `validateOptions` object. I’ve used this to place all error messages into a separate `errorLabelContainer` (like [here](http://stackoverflow.com/questions/61456/mvc-net-jquery-validation)).
|
||
|
||
- I feel that AttachValidator function in `xVal.jquery.validate.js` from could become more loosely coupled by separating the rule conversion from the DOM element attachment.
|
||
|
||
I think both of these jQuery libraries provide a great benefit when creating interactive and helpful forms. Kudos to [Jörn Zaefferer](http://bassistance.de/) and [Mika Tuupola](http://www.appelsiini.net/) for the good work. xVal is likewise an excellent library – thanks to [Steve Sanderson](http://www.codeplex.com/site/users/view/SteveSanderson). |