Web App Common Tasks by jQuery

One of my experience of using jQuery is that I often need to search around for solutions to some particular tasks, although there are good chances that the problems you try to tackle have already been solved by someone else via a plug-in, you still need to digest, evaluate, test and sometimes modify it to fit your project needs. That's perfectly fine for most rapid web development efforts. However, for some browser based, low-level tasks that are common for almost all web applications, searching for multiple plug-ins then put them together and test them out would cost unnecessary time. This article provides a jQuery plug-in (CBEXP) that encapsulates the most common tasks together and is reusable for different web applications.

For example, if your web application needs to conditionally (say, one Ajax call hasn't returned yet) warn user when navigating away or closing the browser window, or your client/service interaction relies on cookies and you want to make sure browser cookie is not turned off, or you need to parse query string and retrieve a particular parameter value in the client, or need to load different stylesheet dynamically without a post back to server, etc., it would be nice to have one jQuery plug in to handle all these low level browser based tasks, then we can focus more on application specific features.

As a matter of fact, CBEXP plug-in was initially put together for a real world consumer facing web application, it has been tested and working, wish it would be useful for your web application too.

This plug in depends on jQuery 1.4.2, Cookie Plug-in and jQuery-JSON plug in, it's designed to be used without a server page (ASP, JSP, PHP, Ruby on Rails, etc.). It certainly can be used with a server page, I just want to point out it works fine with a static HTML file. I usually put it into a public facing landing page, if any browser setting goes unexpectedly, we can tell the user when page loads.

The companion source code has a cbexp_demo.html page is a static HTML page, it shows examples on how the common tasks are performed.

Since all the common tasks will be performed by JavaScript code, the first thing to check would be to make sure browser's JavaScript is enabled, if not, we're going to tell the user it's required and show steps to enable it.

With the cbexp_demo.html page, HTML <noscript> tag is used to show alternative content when end user's browser has JavaScript disabled. The demo page has all the page content wrapped by a "pageContainer" (id) DIV, initially, the page CSS (stylesheets/cbexp.demo.css) hide the pageContainer DIV. If JavaScript is not enabled, all user sees are the content within &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;noscript&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; tag; If the JavaScript is already enabled, the documentReady event handler in cbexp.demo.js will show the pageContainer, see Fig.1 for details.</noscript>

// Fig.1. document ready event handler will not executived if JavaScript is disabled, otherwise it would fade in the page content 

$(function () { $('#pageContainer').fadeIn(); });
Now that we resolved dependencies, let's move onto our first common task by jQuery cbexp plugin.

Check Cookie is enabled
Similarly, we would tell user Cookie needs to be enabled when it's turned off. All these HTML content for no-cookie case is wrapped within a DIV with ID of "noCookieContainer", just like pageContainer, it's initially is set hidden by stylesheets/cbexp.demo.css:

// Fig. 2. Page CSS sets both pageContainer and noCookieContainer hidden  #pageContainer, #noCookieContainer {   display:none;  }

Within the documentReady event handler, it invokes the client side cookie detection method, when it's not enabled, it would show noCookie content. When your web application requires both JavaScript and Cookie, the document ready event handler would become:

//Fig.3 When both JavaScript and Cookie are required, document ready handles the detection and show/hide appropriate content  $(function ()  {   if ($.cbexp.isCookieEnabled())    $('#pageContainer').fadeIn();   else    $('#noCookieContainer').fadeIn();  });

Notice the call to $.cbexp.isCookieEnabled(), it's implemented in CBEXP plug in as a client side cookie detection, it simply tries to write a cookie, if it can read it back, then browser cookie settings is good to go. With the help from jQuery Cookie Plug-in, here is the code for isCookieEnabled:

//Fig.4 Client side cookie detector, writes/reads then remove the detector cookie  isCookieEnabled: function ()  {      $.cookie('cbexp_cookie_detector', 'cbexp_test');      var retVal = ('cbexp_test' == $.cookie('cbexp_cookie_detector'));        $.cookie('cbexp_cookie_detector', null);        return retVal;  }

Certainly, there are many other ways to detect cookie setting, like a round trip to server, but I found this client side approach is easy and quick. If your web application doesn't require cookie, you can then use the CBEXP plugin without the dependency on the jQuery Cookie Plug in.

Beside cookie setting detection, query string parsing is another common task.

Parse Query Strings
CBEXP Plug in has a simple and efficient method to parse out all query string based on current page's URL, in the case of no query string is defined, it returns empty array object. Here is the code:

//Fig. 5 Basic query string pasrsing method with in cbexp plugin
getQueryString: function ()
    var qs = window.location.search;
    if (qs.length <= 1)
        return new Array();
    qs = qs.substring(1, qs.length);
    var a = qs.split("&");
    var b = new Array();
    for (var i = 0; i < a.length; ++i)
        var p = a[i].split('=');
        b[p[0]] = decodeURIComponent(p[1]);
    return b;

A specific query string parameter value can be retrieved by querying the return value of getQueryString, like: $.cbexp.getQueryString()[QueryStringParamName], if the value is defined, it would return a string decoded from URI-encoded string, if not defined, it would null.

Later in this article, I'll show an example to dynamically load CSS and HTML base on different query string parameter values.

What above is about browser information detectyion and information retrieval tasks, let's turn our attention to client-service interactions.

Extend Ajax call with X-HTTP-Method-Override
In our web application, we deliberately desinged our secure RESTful-like web services API to be POST-only or overloaded POST style, when client initiates a service call, it only uses one HTTP verb ---- POST. The main reason is that our web application is targetting regular consumer, each end user may have different firewall settings, some firewalls do not allow PUT or DELETE at all, only GET and POST are OK to go through port 80. Since we still to protect GET requests in our secure web service, so all requests essetially become a POST request.

We gain some consistency in service request side in terms of request body for authentication and authorization information, but we sort of lost some standard operation meanings for HTTP verbs, like the regaulr meaning for GET (read), PUT (create) and DELETE. To solve this service request verb-meaningless-issue and also try to leverage some server side framework's support for HTTP verb (to map certain HTTP verb to corresponding CRUD method in service layer), we extend jQuery ajax API to optionally set X-HTTP-Method-Override HTTP header, similar to what Google Data Protocal does.

The idea is: all service requests will go through a common Ajax wrapper method in CBEXP plugin, by optionally passing in the GET, PUT and DELETE verbs, the method will package the correct headers and settings for the Ajax call, here are the details:

Fig. 6. Ajax call wraper for overloaded POST method with X-HTTP-Method-Override support    
postJson: function (postURL, jsDataObj, onSuccess, onError, httpMethodOverride)
    var beforeSendCallback = null;

        if (httpMethodOverride != undefined)
            httpMethodOverride = httpMethodOverride.toUpperCase();
            if (httpMethodOverride == "GET" || httpMethodOverride == "PUT" || httpMethodOverride == "DELETE")
                beforeSendCallback = function (xhr)
                    xhr.setRequestHeader("X-HTTP-Method-Override", httpMethodOverride);
                    xhr.withCredentials = true;
            beforeSendCallback = function (xhr)
                xhr.withCredentials = true

            type: "POST",
            beforeSend: beforeSendCallback,
            contentType: "application/json",
            dataType: "json",
            url: postURL,
            data: $.toJSON(jsDataObj),
            async: true,
            success: onSuccess,
            error: onError
    catch (err)
        alert("Ajax call error : " + err.description);
Notice it utilizes $.toJSON(jsDataObj) from jQuery JSON plugin to serialize a JavaScript object to JSON string as the POST body.

What above is our extension to Ajax call. In a broader meaning of "Ajax", it not only means interacting with services via XMLHTTPRequest, but also includes dynamically and conditionally loading HTML , Javascript and CSS files to the DOM solely based on client side logic, let's how EBEXP plugin support this as a common task.

Dynamically loading HTML, JavaScript and CSS from client
jQuery is a lightweight while powerful JavaScript library, I was amazed to find out it already had built-in support for dynamically loading HTML by jQuery .load API, and also has a .getScript API for dynamically loading JavaScript file, it definitely enables varies techniques and treatments in terms of building a dynamic web page from client. In the case the client needs to load CSS file at runtime, CBEXP plugin provides a simple easy to use method:

Fig. 7 Support for programmatically loading CSS
loadPageCSS: function (cssUrl)
        rel: "stylesheet",
        type: "text/css",
        href: cssUrl

The method simply creates a new <link></link> tag with proper attributes and append it to page's header. According to the general cascading rules of CSS, the lately loaded CSS will win over previously loaded external CS rules if they have any conflicts.

Although the code looks short and simple, when putting all the pieces together, it really enables some powerful features, like to let client make sure browser has the right settings, to dynamically change page's layout and look and feel (by programmatically loading CSS) based on parameters (by parsing query strings).

Warn the user before they leave
In some use cases, when user tries to leave, either by clicking a link, typing a new URL in browser's address bar, clicking on browser windows's close button, we want to warn the user if they leave some data will be lost. CBEXP plugin supports a programmatic way to enable or disable the warning message. From application perspective, when set the dirty flag, it's anbled, otherwise it would disable. Here below are the code in CBEXP:

setDirtyFlag: function (docDirty)
    $.cbexp.isDirty = docDirty;
    if (docDirty)
        $(window).bind('beforeunload', $.cbexp.confirmExit);
        $(window).unbind('beforeunload', $.cbexp.confirmExit);

getDirtyFlag: function ()
    return $.cbexp.isDirty;

confirmExit: function ()
    if ($.cbexp.isDirty)
        return "Exiting this page will end your session. If you haven't saved your info, it could be lost.";