Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / jQuery

jQuery Validate and Jeditable, Part 2

0.00/5 (No votes)
4 Jan 2010CPOL2 min read 19.3K  
jQuery Validate and Jeditable

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:

XML
<%@ 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:

JavaScript
<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:

JavaScript
{
    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 ViewModel’s rules into this format for JavaScript consumption, this line is added:
JavaScript
<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:

JavaScript
$(function() { // <- on document ready
    // register plug in with Jeditable to tie in jQuery Validate
    $.editable.types['text'].plug in = 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 plug in
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', cell).valid();
}

With this glue in place, the form elements will now be validated with the rules defined in the ViewModel. All fields valid:

jQueryValidateJeditable1

…and here after, both have invalid values:

jQueryValidateJeditable2

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)