When using Jeditable, there is no form element to bind jQuery Validate 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, the View
might be rendered like so for 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’s ClientSideValidation<TViewModel>()
used in Part 1 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 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 rules as attributes to the matched input elements. Since 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 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 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 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.
- To get the
ViewMode
l’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’s “plug in” feature is utilized:
$(function() {
$.editable.types['text'].plug in = bindValidate;
$('.editable').each(function() {
var element = $(this);
element.editable(
'SaveUrlOrFunctionGoesHere',
{
onblur: 'submit',
onsubmit: jeditableValidate,
name: element.attr('name')
}
);
});
});
function bindValidate(settings, self) {
$('form', self).validate(validateOptions);
}
function jeditableValidate(settings, self) {
return $('form', cell).valid();
}
With this glue in place, the form elements will now be validated with the rules defined in the ViewModel
. All fields valid:
…and here after, both have invalid values:
A few notes:
- Any additional options to be sent to jQuery Validate can be attached to the
validateOptions
object. I’ve used this to place all error messages into a separate errorLabelContainer
(like here). - I feel that
AttachValidator
function in xVal.jquery.validate.js form 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 and Mika Tuupola for the good work. xVal
is likewise an excellent library – thanks to Steve Sanderson.
CodeProject