Check for unsaved data on your web forms using jQuery

One of the most important Usability requirements in business applications is, to periodically inform the users when there is any unsaved data on their web pages. This can be seen in email apps like Live mail/Gmail (compose a new mail and try to navigate to Inbox, without saving or sending the mail. An alert will pop out asking to save the mail).

To meet this requirement, one page load, one should loop through all the controls of the page, store the initial values of the controls, bind blur event handlers to all the controls, on blur event compare the final value with the initially stored values. If there is any change in the value, mark the form as dirty (unsaved data), else mark it as clean (saved data).

jQuery Dirty Form plug-in:

I started writing my own code, but found the beautiful dirty form plug-in. Thanks to the author Wilson for the plug-in, which does exactly the same as my pseudo-code. To check for a dirty form, all you need to do is:

$(document).ready(function(){
   $("#YourFormId")
     .dirty_form()
     .dirty(function(event, data){
       //The dirty event fires when you blur from a control after changing its value.
     })
 });

The plug-in is not well documented, hence you should spend time walking through the code. The plug-in will set a flag to the form’s data, to indicate if it is dirty or not, like this:

form.data("dirty", true) 

The dirty() event in snippet 1 will set the dirty flag to true. So at a later stage if you need to check the form’s status, you should use the form’s data. To a good extent I could leverage the the plug-in, but to meet my project specifications, I had to tweak it a lot.

Bug in Dirty Form plug-in and fix for the bug:

The plug-in has a function called “input_checker”, which will check for form status on each control’s blur. As said earlier, it will compare the initially stored values with final ones, which is fine. However, if you switch between forms, the data of one form will be compared with data of latest form, which spoils the show. I’m not sure why others haven’t raised the bug, but I’m very sure of it. Hence publishing the below fix:

In the “input_checker” function, replace the below code

input_checker : function(event){
    var npt... ... ...
    inputs = event.data.inputs, settings = event.data.settings

with this one:

input_checker : function(event){
    var npt ... ... ...
    inputs = $(':input:not(:hidden,:submit,:password,:button)', form), settings = event.data.settings

What is happening is, the plug-in is caching all the inputs to be checked in data parameter of the form. When we navigate to a new form, the controls of old form(from cache) are being checked, instead of the controls from new form. Hence I am querying the controls of new form again and using it for comparison. This would solve the problem :)

Here are some of the functionalities which I could leverage using the plug-in:

(1) On page load you can disable save buttons and enable them only in the dirty() event.

(2) You can check for form dirty flag and decide to extend user’s session accordingly.

(3) You can give a warning when user navigates to another page without saving data (similar to Gmail/Live mail).

Thanks to Wilson once again for the plug-in. Hope the fix would help some of the folks who are facing similar issues. 

Happy coding :)

Client side localization in ASP.NET using jQuery

Localization is a very important feature required in medium-large scale business applications. As always, ASP.NET makes developers life easy by providing inbuilt localization mechanism. Using resource files, all the elements in a web page can be localized.

However, if you are building a rich client side app using JavaScript/jQuery, you may need to fetch error messages and other strings from locale specific external file, without post back. In such cases, jQuery localization plugins come to rescue. Below are some of the best jQuery plugins, which help in localization:

  1. http://keith-wood.name/localisation.html
  2. http://codingwithcoffee.com/?p=272
  3. http://sundaymorning.jaysalvat.com/ 

The third one is cool with integrated Google translation API,  The second plugin is used by jqGrid & other plugins for localization. However, I really loved the first one - Keith wood's plugin, which gives a basic but powerful localisation features. All it does is, make synchronous call to the server and load locale specific JS file, which will override the variables of your base file. When you use custom events to change localized messages, the first one is the best, owing to its simplistic nature.

The question now is, how to get the UI culture of user's browser on page load.

Though the plugin is expected to do this, somehow, this is a missing feature. But you need not worry, as ASP.NET does this easily for you.In the "Session_Start" event of global.asax, just use this code:

Response.Cookies("UICultureCookie").Value = Request.UserLanguages(0)

This stores the first preferred UI culture of user's browser in a cookie. Using the information in this cookie is pretty simple using jQuery's cookie plugin. Just say:

var clientCulture = $.cookie("UICultureCookie");
$.localise('JavaScript/Constants/constants', { language: clientCulture }); 

That's it!  Now even your client side messages in ASP.NET can be localized, without postback, using the power of jQuery.

P.S:  I didn't write much about how to use these plugins, as their home pages have clear documentation & demos, which are self explanatory.

Using jQuery cluetip plugin for validation callouts.

Displaying validation messages using callouts is a good way of educating the user on what has to be filled on the form. ASP.NET AJAX's Validator callout does a good job in this aspect. But how about implementing the same using jQuery?

I was googling for this and quickly came across jQuery validator callout plugin. This is an excellent plugin which suits many forms. However, I could not use it as it displays callout either on the top or bottom of the textboxes. I need callouts to be displayed to the right/left side of textboxes. I tried to customize it, but without much output. So tried for other options.

It struck me that I can use jTip for this requirement. However, jTip expects every call to be an AJAX call. So finally came to clueTip and yeah, I'm on the right track. The output would be something like this:


One good point which makes me feel this approach is better than ASP.NET AJAX toolkit callout is, unlike the toolkit callout, I need not write HTML for each and every popup. Just place the div at one place in your mark up and hide it. Reuse that piece for every call out.

How to use clueTip as Validator callout?

First, please check how clue Tip works. If you are aware of how to use clueTip, the below code would be a cake walk.

1. Place a div in your HTML like this: <div id="ValidationMessageDiv"></div>

2. Create 2 JavaScript functions "showCallOut(element,errorMessage)" and "removeCallOut()".

3. In the validation code for your "Submit" button, write this:

$("#SubmitButtonId").click(function() {
   if (ContactNumberText.val() === '') {
      showCallOut('ContactNumberTextId', "Please enter contact number"); 
    }
}); 

That's it! You can now use the showCallOut(,) function in every button click.

Here are the definitions of the fuctions used:

function showCallOut(element,errorMessage) {
    element = '#' + element;
    $(element).addClass('jt ui-state-error').attr('message', errorMessage);
 
    var firstErrorElement = $('.ui-state-error:first');
    var firstErrorElementTop = firstErrorElement.offset().top;
 
    $(element).attr('title', 'Required field')
        .attr('rel', 'div[id="ValidationMessageDiv"]')
        .cluetip({
            local: true, cursor: 'pointer',
            cluetipClass: 'jtip', width: '150', //sticky:'true',
            arrows: true, dropShadow: false, hoverIntent: false
        });
    firstErrorElement.focus();
}
 
function removeCallOut() {
    $('.ui-state-error').unbind('focus.cluetip');
    $('.ui-state-error').removeClass('jt ui-state-error').removeAttr('message')
        .removeAttr('rel').removeAttr('title');
} 

I just made the showCallOut function a bit intelligent, so that if a form has 10 mandatory fields, it will add "ui.state.error" class to every control (Remember? This class is jQuery ThemeRoller's class for highlighting error controls). By default the first control will be focussed and callout comes out. If you switch the focus to another control, the callout disappears for first control and reappears for second control.

If you want to remove the callout after validating the field, just use the removeCallOut() function.

This is just an idea for those who are struggling with similar requirement. I will try to come up with a demo so that it would be more clear.