How to Maintain Browser History When Using AJAX

One of the biggest problems when using AJAX in web development is maintaining application state. In a javascript heavy site one might want to do all sorts of things that change the state of the user experience. For instance, opening up modal dialogs (popups) over the page to request input from the user, etc. Because these state changes are occurring only with javascript the browser is technically unaware of what is going on. If the user decides to hit the back button thinking they are just going back to before they opened a popup, they will be surprised when it takes them several steps backward to the last point where their browser actually made a full request. Similar issues occur when they refresh the page. The dynamic state is totally blown away and a new page request is made.

CodeTunnel suffered from this on the blog index page. When javascript is turned on in the user's browser CodeTunnel will AJAXify the paging links on the blog index. A cool little loading animation occurs as they change pages rather than the plain old browser page loading. Because the pages were loaded with AJAX the URL never actually changed; it would simply say "www.CodeTunnel.com" the entire time. This caused refreshes to take the user back to page one every time. Visitors also could not link to a specific page of blog summaries if they wanted a friend to see them.

I did not realize how easy it would be to actually solve this problem until I discovered a little jQuery plugin called jQuery.history. This plugin is very minimalistic and takes almost no effort to setup. What it does is actually pretty creative. jQuery.history monitors the URL of your page and looks for changes to the hash tag. You may have seen the hash tag used on other websites to link to content within a single page. Most browsers do not do a full page load when they see this tag; they know that the link is to content within the same page and it simply scrolls you to that content. If there is no content marked with an anchor matching the hash tag, it does nothing at all. jQuery.history takes advantage of this and uses it to modify the URL without doing page refreshes.

What I did here on CodeTunnel was, instead of making an AJAX call when a link is clicked, the link just changes the url by suffixing it with a unique hash tag. jQuery.history then sees that the hash tag was changed and runs some javascript to make the AJAX call. Because the URL did change, the browser is capable of navigating through the hash tags with the back button. Even the refresh button works properly in this scenario.

Implementation was simple. First simply reference the jquery.history.js file:

<script src="/Scripts/jquery.history.js" type="text/javascript"></script>

Then run an initialization method once in the DOM ready:

$(function () {
    $.history.init(function (hash) {
        if (hash == "") {
            // initialize your app
            // runs when page first loads.
        } else {
            // restore the state from hash
            // (i.e. in "http://www.CodeTunnel.com/#/Blog/Page5"
            // the hash var would contain "/Blog/Page5".)
        }
    },
    { unescape: ",/" });
}

The first option passed into $.history.init() is a callback function. This function runs every time the hash URL changes as well as when the page initially loads. This function would be where I placed the code to perform my AJAX calls to change the page. The second option passed into $.history.init() is a JSON with one property called "unescape". This property contains a string of characters that should not be URL encoded. For instance, if you don't want spaces in the url to get turned into %20 then put a space in that string (ex: "http://www.CodeTunnel.com/#some hash variable" would not get turned into "http://www.CodeTunnel.com/#some hash variable" if you supplied a space in the unescape string.).

Now all you have to do is make your links include hash tags. It's also possible to change the hash tag with javascript by calling $.history.load(hash), passing some value in place of hash. This will change the URL and run the callback function like normal.

I highly suggest you check this plugin out if you want to maintain application state and still take advantage of AJAX and all its awesomeness!