Check which rule is not fullfiled in jQuery validate plugin

Recently, I have encountered a situation where I used jQuery validation plugin and needed to know which of validation rules are failing. After asking this question on http://stackoverflow.com/questions/7648727/jquery-validate-check-which-rule-is-not-fullfiled and receiving no answers for 15 days, I have spent some time to solve it by myself.

It turned out quite easy, after inspecting source code of plugin on https://github.com/jzaefferer/jquery-validation/blob/master/jquery.validate.js, I have found out that this can be done by adding my own function to it:

 

$.validator.prototype.ruleValidationStatus = function( element ) {
    element = $(element)[0];
    var rules = $(element).rules();
    var errors ={};
    for (var method in rules ) {
        var rule = { method: method, parameters: rules[method] };
        try {
            var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
 
            errors[rule.method] = result ;
 
        } catch(e) {
            console.log(e);
        }
    }
    return errors;
}

This function returns list of validation rules with their results, and usage is simple:

$("#myform").validate().ruleValidationStatus($("#myField"));

Deserialize form from JSON data using jQuery

Recently, I got task to make feature which will make possible for user to update form data based on some unique “search” field (like VIN or SSN). I wanted to make this short and simple, and above all reusable. So, I made some investigation this weekend and came up with simple solution to use same model object that is used as type of view in asp.net mvc. It is simple javascript function:

 

var formPrefix = 'myFormPrefix';
$('sometextbox').change(function () {
 var myValue = $(this).val()
 $.ajax({ type: 'POST',
  url: 'ajaxcontroller/getcarbysomething',
  data: { something: myValue },
  success: function (data) {
  if (data){
   $("input[name*='" + formPrefix +"'],select[name*='" + formPrefix + "']").each(function () {
    var itemName = $(this).attr("name");
    var prop = itemName.substring(itemName.indexOf(formPrefix) + formPrefix.length);
    var itemValue = data.person[prop];
    if (itemValue && itemValue.substring &&
      itemValue.substring(0, 1) == "/" &&
      itemValue.substring(itemValue.length - 1) == "/") {
         itemValue = "new" + itemValue.substring(1, itemValue.length - 1);
         itemValue = eval(itemValue);
         $(this).datepicker("setDate", eval(itemValue));
    }
    else if (itemValue) {
     $(this).val(itemValue);
    }
   });
 
   }
  }
 });
});

So, to use this you need to make controller action that returns JsonResult and Json(model) instead of View(model). If form is partial view (preffered) or has explicit prefix, formPrefix is place to set it. Each form input element’s name is used to index json object returned from controller and value (if any) is set back into input element.

Autocompleting cascading dropdowns

 

Starting point for this post is source code for last one, available on bitbucket.

I want to replace dropdown list with jQuery autocomplete, like in this example. There are two reasons for this:

  • When there is very large number of records to choose from, then standard dropdown list is not very user friendly
  • When user is entering name of item, besides autocompleting from known items, we can implement addition of new item if item user needs to enter is not present in codebook. This will be done in next post.

For start, I will copy example from jQuery demo, and add textbox in which I will implement this functionality.

image

I have added this code to Index.chtml, which is label for manufacturer, hidden field with id for chosen value from dropdown, and textbox for autocomplete. I have added three attributes for this textbox:
– autocomplete-for is target (hidden field) into which I want to place chosen value
– from-url is address where I will get items for autocomplete
– parent is field for cascading functionality (this will be optional)

Client side code for autocomplete is based on jsonp example from jQuery ui demo:

image

I have added this init function to document ready event. What is happening here is simple: for each input element that has “autocomplete-for” attribute, jQuery autocomplete is added, with custom function as data provider. This function is using ajax to request data for dropdown from from-url specified in view. Parameters are MaxItems (amount of items to show in autocomplete), ParentFilterId (selected value of parent field – for cascading support) and NameStartsWith, which is text entered into dropdown which is autocompleted.

Success function maps “items” collection in response to label, value and id. label and value are automatically used by autocomplete plugin to show label for item in dropdown and to set textbox value when item is selected, and I added id to set hidden field in select event.

To make this work, there is one thing left: controller action which will return items. As you can see in first screenshot, I decided to use Manufacturer controller and action named Autocomplete.

To make parameter passing easier, I have created model for data passed in request:

image

I will receive this object as parameter in my action.

This is how implementation of autocomplete action looks:

image

This is fairly simple – query is filtered by name for NameStartsWith parameter, and I used ToLower method of string, to compare case insensitive, as StartsWith with string comparison options parameter is not supported in linq to entities.

If request contains parent filter id or max items number, then these are taken into account, and response is formed as collection of items with Text, Value and Id properties, which are used in success function of ajax request.

Time to see how it works:

imageimageimage

As this is working nicely, time for little makeup, as I want this more reusable, and not having to remember html attributes that need to be used. So, that smells like html helper:

image

Actually, it is two helpers – one for cascading case, and one for “normal”. It is the same code as in cshtml view, but creating hidden and text field in one method, and when I add comments here (removed to make screenshot smaller), I will have nice intellisense to use this function whenever I need, only having to copy and adjust controller action, which also can be made pretty generic.

 

image

This is how autocomplete is used now. I’m ready to call this a day, and source code from this post is in this changeset on bitbucket.

ASP.NET MVC3 app (part 3) – ajax cascading dropdown–unobtrusive version

 

In part 2, I made cascading dropdowns by calling selectFromAjax javascript function from my view:

image

This function has 3 arguments: address of service which provides data based on second argument – formData (in this case only id of selected item in current dropdown), and target – select list into which items from service are injected, replacing its current contents. These three parameters are almost enough to know that there is dependency between two dropdowns. Why almost? Because there is one implicit parameter – this function is part of “change” event of another dropdown – source of this event. So, source dropdown is fourth parameter. That four things are everything that client needs to know to be able to implement intended behavior of UI.

I will make this functionality unobtrusive by placing necessary information into target dropdown. Why? Because it seems most straightforward and “unobtrusive” to me, that dropdown list says “My contents depend on item selected in dropdown list X, and you need to call service Y to find out what should I show”. It is not ok to have information about MY behavior in some other dropdown X Smile. Besides, with this approach, I’m eliminating one parameter, as I have only two now: dropdown X and service Y. Third was value of dropdown X, and fourth is target dropdown itself, into which I’m adding these attributes. Value of dropdown X I can read if I know which is dropdown X, so this parameter for function anyway must be determined at the moment of changing value in X.

So, if I make my select look like

image 

then my dropdown contains all information needed to remove script from view, and place it in global js file, or make jQuery plugin. To make this information automatically embedded into my dropdown, I need to make html helper for this. If wee look at first overload of DropDownListFor in System.Web.Mvc.Html.SelectExtensions, we can easily see how new method should look:

image

My html helper will have another two arguments – depends on and load from:

image

It is using DropDownListFor helper from Microsoft, and I won’t render my own html code (and so make more space for bugs Smile).

So, view from part 2 should now look like this:

image

and generated html is:

<select cascading-dependson="ProductType" cascading-loadfrom="/Home/Manufacturers" id="Manufacturer" name="Manufacturer"></select>

Now, all that is left, is to automatically attach event handler onto “master” dropdown. It is easy using jQuery:

imageThis is adding initializeCascader to list of functions that are run on document load. This function goes through each select that has cascading attributes and attaches onchange event to element with id in cascading-depenson attribute, with self as a target for selectFromAjax function (from part 2), and value of cascading-loadfrom attribute as a url.

This is very simple concept, but can be used for chaining random number of dropdowns, and can easily be expanded to make dropdown values dependent not only on “master” dropdown, but to depend on whole form. Further improvement of this could be custom data annotation attribute, which could be used for decorating property of model, so html helper does not have to be explicitly called.

Source code for this post can be downloaded here.

UPDATE: I have uploaded source code to bitbucket.

Back to part 2

ASP.NET MVC3 app (part 2) – ajax cascading dropdown

 

To make cascading dropdowns in application from part 1, I created ProductFilter:

image

I will use this class as model for my home controller Index method:

image

Here you can also see Manufacturers JsonResult method, which is used for asynchronous refresh of second dropdown:

imageimage

Manufacturer dropdown is loaded with manufacturers which produce models of chosen product type. This is made possible with simple jquery function:

image

This function accepts url of method which provides json list of items for dropdown, passes formData parameter with id, and places results into target for which selector “target” is provided.

This is how my view from which this method is called looks:

image

Two dropdowns are created using standard MVC helpers, and onchange event function is attached using jquery. More dropdowns can be chained in the same way, there is only necessary to add change function in the same manner. However, this is no good, as event attachment is manual, and script must be written, and included into view as selectors are generated here. My goal is to make these event attachments unobtrusive, and I will write about that in part 3.

For now, you can download project source code here.

Back to part 1