The software development blog of James "poprhythm" Kolpack RSS 2.0
# Sunday, January 03, 2010

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

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 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 and Mika Tuupola for the good work.  xVal is likewise an excellent library – thanks to Steve Sanderson.

Sunday, January 03, 2010 12:47:00 AM (Eastern Standard Time, UTC-05:00)  #   
Comments [0] -
# Thursday, December 31, 2009

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.  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 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 by Elijah Manor who mentioned using xVal for robust server and client side validation. And with the news that MVC 2 will have a built in validation technique similar to xVal, it was an easy decision to start investigating this library.

xVal 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, 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 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 via Castle ActiveRecord 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’s built-in jQuery Validate 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’s dynamic inline forms to be not so straight forward.

Continued in Part 2

Thursday, December 31, 2009 10:32:00 PM (Eastern Standard Time, UTC-05:00)  #   
Comments [0] -
# Wednesday, December 30, 2009

Interacting with your computer using a mouse-driven GUI makes many tasks quick and easy to accomplish.  However, when use of the keyboard is required, a healthy amount of context shifting between these two non-complimentary input devices can occur.  And that’s bad news for turning thoughts into actions in a timely matter. So, what’s the consequence of spending a few extra seconds to switch back and forth?  As John D. Cook points out, it adds up:

It’s a matter of keeping up with your thoughts. Suppose some series of tasks takes 20 seconds with a mouse but you can accomplish the same tasks in 12 seconds using the keyboard. The big deal isn’t that you’ve saved 8 seconds; the big deal is that you’re more likely to finish your tasks before you lose the thought that motivated them.

I interact with theTilda - Console Launcher Hot Key file system on a very regular basis.  I haven’t measured this, but I bet I’ll open Windows Explorer (or xplorer²) at least two or three times for every hour I’m at the computer.  I’m forever poking around for documents and restructuring directories so that they’ll be easier to find next time.  Many times I’ll want to execute a command line statement in the path that I’m browsing.  There are several different strategies for getting a “Open Command Prompt Here” to the explorer context menu, but they all require a right-click (or simulating one with the keyboard).  There’s an easier way.

A couple years ago I read an article on instructables about a “Drop Down”, Quake-style command prompt for Windows.  The project uses AutoHotKey to launch and hide a console window using a keyboard shortcut.  Neat!  It works great, except that it always dumps you in the your %HOMEPATH%.  I’ve taken the script and upgraded it to navigate directly to the currently open path in Windows Explorer – it’s name is Tilda.

For example – I’ve got an explorer window open in C:\console\UnxUtils\usr\local\wbin and I want to string some of those juicy unix command line utilities together.  I can now simply do Win+~, and I’ve got a new console instance in the right place.  As with the original, it will minimize/maximize the console window on subsequent usage of the key combination. 

I have this nasty habit of navigating around the file system when I’m using Windows Explorer.  After running some unix commands, I might have a hankering to run MSBuild.exe (ok, probably not, but who knows?).  I could tediously type the path, or, I could have Tilda automatically enter it for me.  From the new path in Windows Explorer, I type a combination Win+Shift+~ and the chdir command gets sent to the current console window.Tilda - chdir

Please note that I’m using (and recommend) Console as a command line window host.  Tilda is currently set to use this, but the script can be easily modified to use cmd.exe or whichever console window host you prefer.

Tilda - open and close a console window using a hot key.  Automatically navigates to the currently open explorer window.  Save some trips to the mouse and make getting to the command line easier.

Download Tilda (AutoHotKey source and binary)

Wednesday, December 30, 2009 5:01:00 AM (Eastern Standard Time, UTC-05:00)  #   
Comments [0] -
# Saturday, December 12, 2009

Hi, I’m James Kolpack, and I’m a code-aholic.

Where I’m from

Ever since I was a kid I’ve been programming at various degrees of sophistication.  Being a child of the 80’s, I started with Basic (of the GW variety on a 8086 based IBM) with a dash of Logo and batch scripting.  Later in college I became learned in Pascal and then C and the trials and tribulations of memory management and complex data structures.  I loved the ability to solve interesting problems by the clever assembly of instructions to be executed on a computer.  It was a bit of a power trip, really - “Pow, I just made a program that can find the optimal combination of items to fill a knapsack in psuedo-polynomial time.”  This capability does not, I discovered, transcend one-to-one to “real-world” power – but you’ve got to LegoMan_biggerdo what you can with what you’ve got.

As for the name of the blog, “popcyclical”, it’s a dual homage to my interest in cyclical relationships and, of course, popsicles.  It also references my moniker “poprhythm” which I was given many years ago for my ever-loving devotion to excellent music.

Where I’m going

On this blog I will be exploring ideas and issues that are relevant to me at the given time.  As a developer employed at a small shop, 100px-Directed_graph_with_back_edge.svgthe focus is guaranteed to wander over time.  For any given week, I may be highly invested in any number of   topics.  This may include : upcoming features of programming languages, graph algorithm design and application, development tooling, data mining, system architecture, user experience, natural language processing, semantic web, test driven development, statistics, data management, … these and many others are all fair game.  As of today, the technologies I’m working in from day to day are C# on the .NET framework, ASP.NET MVC and jQuery, WCF, and a variety of database engines.

I can use your help

When pointing the finger of blame for a problem I’m faced with, more often than not, that finger will eventually turn back to point at myself.  To err is human, and for software creators, this is repeatedly beaten into our skulls. Every time a compile fails, a stack overflows, a user is confused with our design, an out of memory exception is thrown, and every other time we’ve had a slip of the finger or a misconception about the problem or a technology. To combat this, we must flock together to overcome our individual weakness.  I welcome all relevant comments, suggestions, and criticism.

Saturday, December 12, 2009 10:17:00 AM (Eastern Standard Time, UTC-05:00)  #   
Comments [2] -
Linkroll
Archive
<January 2010>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2012
James Kolpack
Sign In
All Content © 2012, James Kolpack
DasBlog theme 'Business' created by Christoph De Baene (delarou)
ASP .NET Web Hosting By Arvixe