- We design and build extraordinary applications for companies looking to make the next great idea a reality.
- learn more
dsHistory: A novel approach to Ajax history and bookmarking
Besides providing a useful tool to other developers, my chief interest in taking over Brad Neuberg's Really Simple History was to test the limits of my own JavaScript and browser-hacking skills. Version 0.6 was basically a maintenance release designed to acquaint the library with the browsers that had come of age since its initial 2005 release. The forthcoming 0.8 will be more of a redesign, adding new functionality while taking advantage of more modern JavaScript programming idioms. Lazy function definitions will improve performance, while closures and internal functions will lock down several methods that are currently public but need to be private.
Andrew Mattie is also hard at work modernizing his own Ajax history library: dsHistory, which just came out with a new release. I've been playing around with dsHistory, and I have to say I'm impressed. The differentiating feature of Really Simple History is its ability to maintain history states even after the user navigates away to other sites and back again. The unique thing about dsHistory, however, is its ability to bind the back button to arbitrary JavaScript functions without touching the URL fragment identifier. It's always interesting to see how other developers solve the same problems, often by slightly reframing them. Their differing outlooks make the two libraries suitable for different audiences, but there's also a lot of common ground.
In RSH and other Ajax bookmarking frameworks, each history point creates a new URL hash value, resulting in a unique, bookmarkable URL. In dsHistory, however, the history stack is implemented as an internal JavaScript object; the generation of bookmarkable URLs is optional. When you do choose to set a new bookmarkable URL, you do so by setting the URL fragment identifier to a pseudo-querystring of key-value pairs. The result is a library that turns the back and forward buttons into "undo" and "redo" buttons and optionally generates bookmarkable URLs that contain all the data necessary to "rehydrate" the application to its previous state when accessed from the bookmark.
It's possible to use Really Simple History in the same way you can use dsHistory. Normally, RSH creates history points as a key-value pair. The key serves as the URL fragment identifier, while the value, which can be any arbitrary JavaScript type (including complex objects), gets saved in a hidden form field. This means you can store an enormous amount of information for each history point in the application. But it also means that you lose all of that information if you return to that application state from a bookmark. The bookmark retains the key, but the value gets lost. To get around this constraint, many RSH users simply ignore the value in the key-value pair, and turn the key itself into a series of key-value pairs. Each approach is valid, depending upon the needs of your application. Consider the following examples:
//Method 1
var key = "applicationState1";
var value = {appData1: "a string", appData2: 2, appData3: true, appData4: ["an","array","of","strings"], appData5: {propertyOne: "1","propertyTwo: "Two"}};
dhtmlHistory.add(key,value);//Method 2
var key = "appData1=a string&appData2=2&appData3=true&appData4=an,array,of,strings";
var value = null;
dhtmlHistory.add(key,value);
The first method is great for Ajax operations that involve a lot of data that needs to persist only within the context of the current browser session. Example: an "undo" stack in a spreadsheet application. The value can be a large associative array, but it will be lost if the user bookmarks the page and returns. The complete spreadsheet data can be serialized in each history point so that the user can easily undo changes with the back button; upon returning from a bookmark, though, the undo stack will be empty.
The second method is more suited for Ajax operations in which a finite number of data points need to be associated with each history point and the application needs to be able to recover these data points when accessed from a bookmark. Example: A survey application in which users choose answers to a number of questions using HTML dropdowns. If the user bookmarks a half-completed survey and returns, he'll be able to pick up where he left off.
From comments on the RSH mailing list and issue tracker, it seems like this second method is pretty common among RSH users. It therefore makes a lot of sense that this is the default behavior for dsHistory. Mattie's library doesn't, as yet, support Opera and Safari; it also offers no built-in ability to recover after the user navigates to another site and then back to a dsHistory-enabled application. Still, Mattie's code works solidly in IE and Firefox, and he's hard at work building toward a 1.0 release. Despite being a much younger framework than RSH, he'll probably get to 1.0 sooner than I do. I'm looking forward to seeing how he tackles Opera and Safari, which caused me no end of grief in my own development.
For examples of dsHistory in action, check out Mattie's thorough example page. [Reminder to self: Make my users happy and flesh out my FAQs and usage examples!]
Topics: Ajax Bookmarking, Really Simple History
Comments: 1 so far
Leave a comment
About Pathfinder
Recent
- Walk-Through Test Coverage
- Where minimalism fails: The problem with Apple’s less-is-more approach
- jQuery goodness with ASP .NET
- Design Thinking
- Bullseye Diagram
- Roles Testing For Security
- Blackbird takes the pain out of JavaScript logging
- Making GWT JSON not Quite so Painful
- IDEA - preconference workshop 06 Oct 08
- HTML5, Ajax history management, and The Ajax Experience 2008 Boston
Archives
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006


Thanks for the hat tip Brian!
As you noted, dsHistory acts more like an “undo” / “redo” enabler. Unlike RSH, dsHistory generally can’t keep up with the back / forward buttons after a user has gone on to another page and subsequently back to the dsHistory-enabled page. If the user _did_ end up arriving at the dsHistory-enabled page via the back button after having moved on, it’s definitely possible that they could have a bad user experience if they continued to use the back button after reaching the page again. To me, this limitation just means that dsHistory will never be the right choice for every app and set of circumstances / requirements.
That said, I’ve really enjoyed working on dsHistory; it has certainly presented some unique development challenges that I hadn’t encountered elsewhere. I studied RSH quite a bit before I initially built dsHistory back in Apr ‘07, and I’ve been looking over your recent work to get some idea on how I can implement support for Safari 2 and Opera in my own library. It seems like it’s going to be a lot of work, but I’m really grateful that I don’t have to start from scratch like you did!
Have you considered creating unit tests for RSH? The complexities I encountered while developing dsHistory make it really hard to ensure bug-free functionality across all browsers, so it’s an absolute requirement for me to finish some unit tests for cross-browser functionality before I reach v1.0. I’ve narrowed my choices down to Selenium ( http://selenium.openqa.org/ ) and JsUnit ( http://www.jsunit.net/ ), but I was just curious to see if it was something you had considered or done research on.
Anyway, thanks again for the writeup and compliments.
Comment by Andrew Mattie, Thursday, February 7, 2008 @ 1:10 am