Using JSON Objects as RSH Location

In the past year, many sites have upgraded to use AJAX, loading dynamic content to their sites with JavaScript and some server side data format. This is a huge boon, to the UI as it is no longer the click and wait paradigm of Web 1.0. However, the downside of JavaScript loaded, dynamic content is that is not bookmarkable and breaks the history flow the client browser.

At the end of last year, we saw many companies competing to produce the best JavaScript history manager, including big names like Google and YAHOO. In the coming year, I believe most AJAX sites will start including a history mechanism. I am putting my support behind Really Simple History (RSH). As, I have mentioned before, RSH is simple, clean, and easy to use. It is also getting continued support by Brian Dillard of Agile Ajax.

Really Simple History

RSH is easy to use, and I believe Brian does a good job at explaining how it works. For the rest of this article, I will assume, you have everything included properly and understand basically how RSH works. You might have written code that looks something like the following for managing history on a page:

Example 1: RSH Module Example

var pageController = function() {
	
	// pageController Module Constant Variables
	
	var DEFAULT_LOC = {"param1":"value1", "param2": "value2", "param3": "value3"},
		LOC_PREFIX = location:; // default JSON object for location
	
	// pageController Module Local Variables
	
	var F = function() {},
		that = null;
	
	
	// pageController Module Event Namespace
	
	var evt = {
	
	
		/**
		 * Example event that adds a history value
		 *
		 * @method ajaxEventExample
		 * @param e {event} the triggered event
		 * @private
		 */
		ajaxEventExample: function(e) {
			// some logic on the event
			// assume logic creates value1, value2, and value3
			var loc = PREFIX + {"param1":" + value1 + ", "param2": " + value2 + ", "param3": " + value3 + "};
			dhtmlHistory.add(loc, null);
		},

		/**
		 * A function that is called whenever the user presses the back or forward buttons. This function will be passed the newLocation,
         *     as well as any history data we associated with the location.
		 *
		 * @method onChangeHistory
         * @param newLocation {string} the location
         * @param historyDate {object} the history
		 * @private
         */
		onChangeHistory(newLocation, historyData) {
			var loc = unescape(newLocation) || LOC_PREFIX + DEFAULT_LOC;
			
			if (loc && window.location.hash !== loc && -1 < window.location.indexOf(LOC_PREFIX)) {
				var json = unescape(loc.replace(LOC_PREFIX, )).parseJSON() || DEFAULT_LOC.parseJSON();
				that.updateWidgetFunction(json.param1, json.param2, json.param3);
			}
		}
	};
	
	
	// Public Functions and Variables
	
	F.prototype = {
	
	
		/**
		 * An example update method
		 *
		 * @method updateWidgetFunction
		 * @param param1 {string} value1 from location JSON
		 * @param param2 {string} value2 from location JSON
		 * @param param3 {string} value3 from location JSON
		 * @public
		 */
		updateWidgetFunction: function(param1, param2, param3) {
			// update logic
		}
	};
	
	// scope that variable to this
	that = new F();
	
	/** START - RSH SETUP LOGIC **/

	// add history listener function
	dhtmlHistory.addListener(evt.onChangeHistory);

	// fetch the current location, if any
	var initialLocation = dhtmlHistory.getCurrentLocation();

	// if no location specified, use the default
	if (initialLocation) {
		evt.onChangeHistory(initialLocation, null);
	}
	
	/** STOP - RSH SETUP LOGIC **/
	
	// return public methods
	return that;
}();

This example shows a complete template for using RSH included in a page controller. Modify this to your liking and include it as the last file on your page (if not the end, then at least after rsh.js is included) to get RSH to work. Now lets discuss how to use JSON with RSH:

First, prefix all locations with a unique string; in this example we use location: as the prefix. The prefix is important for filtering "window.hash" changes so they do not break your code, as your history code path wont execute if the location prefix is not present. It also, helps for readability of the location portion of the URL.

Second, when we use the history (add and update) we convert our parameters to a JSON object in String format. "json.js" will be included in the project anyway (or an equivalent package) for use with RSH, so you can leverage it to convert JSON objects to and from strings, otherwise, you can do it manually as I have in the add function. It is important to unescape the retrieved location in the history callback function as the history code will have escaped it before adding it to "window.hash".

Using these techniques you can now store your RSH location history as a JSON object, which is helpful if you typically use JSON objects to store JavaScript data or you were simply confused how this worked. If you prefer JSON objects, then you will have to do one less conversion in your code, and JSON objects are a robust and well-known format.

Hopefully, you also now have the understanding of RSH to modify this code to support storing the history as a query string or some other mechanism. Feel free to comment if you have any questions.

Web Development News October 10, 2007

Really Simple History Update

The really simple history project is being taken over by Brian Dillard. He is revamping it to use the Module Pattern and compliant methods wherever possible. For more information see my article:

More on Really Simple History

And Brians:

Coming Soon: Really Simple History 0.6 Beta

Really Simple History Continued (Part II)

So contrary to my last post, it does work in Internet Explorer. I had accidentally overwritten their blank.html file with the one used by YUI. This file is required for the IE IFRAME and contains a callback to window.parent (the browser window that you are using dhtmlHistory in). If the following is missing, then IE wont work:

<script language="JavaScript"> function pageLoaded() { window.parent.dhtmlHistory.iframeLoaded(window.location); } </script> <body onload="pageLoaded()"></body>
I never did manage to get it ...

Really Simple History

For my Mint project, I have been asked to capture the back button and simulate browser history for AJAX GET requests. We do a lot of AJAX magic on the site that looks to the average web user as if the page has reloaded, such as requests to: sort, search, filter, and paginate bank transactions. The product/marketing teams expect instant, desktop-like response (hence the AJAX), but they expect the browser to behave as a ...