Dynamic web applications that avoid page refreshes are very powerful, but this normally means that the Back and Forward buttons stop working in the browser. In addition, it can be hard to give the user an URL that can be bookmarked.
However, Dojo provides a solution to these issues, allowing a web application to capture the Back and Forward button clicks, and set a unique URL in the browser's location field. The solution is to use dojo.undo.browser.
The behavior described in this document is different from the 0.2.2 Dojo release. In that release, it was not very easy to track the state that corresponded to a "page", but it was possible to register callbacks for Back and Forward through a dojo.io.bind() call. For 0.3 and later, the Back/Forward/Bookmarking support was moved to a new module, dojo.undo.browser. As a result of the changes, you may see slightly different behavior as compared with 0.2.2. The main difference is the need to call dojo.undo.browser.setInitialState(state) to set the state for the page as it is first loaded by the browser.
Dynamic web applications that use things like XMLHTTPRequest and DOM updates instead of page refreshes do not update the browser history, and they do not change the URL of the page. That means if the user clicks the Back button, they will likely jump all the way out of the web application, losing any state that they were in. It is also hard to allow a user to bookmark the web application at a certain state.
Dojo's dojo.undo.browser module will introduce browser history so that it is possible for the user to click Back and Forward without leaving the web application, and the developer can get notification of these Back and Forward events and update the web application appropriately. Browser history is generated by using a hidden IFRAME and/or adding a unique value to the fragment identifier portion of the page URL. The fragment identifier is the #value thing in a URL. For example:
http://some.domain.com/my/path/to/page.html#fragmentIdentifier
Since changing the fragment identifier does not cause the page to refresh, it is ideal for maintaining the state of the application. The developer can specify a more meaningful value for the fragment identifier to allow bookmarking.
dojo.undo.browser allows setting a state object that represents the state of the page. This state object will get callbacks when the Back or Forward button is pressed. In addition to registering state objects with dojo.undo.browser directly, the state object can be passed to dojo.io.bind() and it will be added to dojo.undo.browser for you.
The following prerequisites are needed to use dojo.undo.browser:
Register the initial state of the page by calling:
dojo.undo.browser.setInitialState(state);
This state object will be called when the user clicks Back all the way back to the start of the web application. If the user clicks Back once more, they will go back in the browser to wherever they were before loading the web application.
The state object should have the following functions defined:
Example of the a very simple state object:
var state = {
back: function() { alert("Back was clicked!"); },
forward: function() { alert("Forward was clicked!"); }
}; To register a state object that represents the result of a user action, use the following call:
dojo.undo.browser.addToHistory(state);
or, if you are using dojo.io.bind(), if the object contains the function back() or backButton() or the property changeUrl, then dojo.io.bind() will call dojo.undo.browser for you (only works with XMLHTTPTransport and ScriptSrcTransport).
To change the URL in the browser's location bar, include a changeUrl property on the state object. If this property is set to true, dojo.undo.browser will generate a unique value for the fragment identifier. If it is set to any other value (except undefined, null, 0 or empty string), then that value will be used as the fragment identifier. This will allow users to bookmark the page.
There are test pages that shows how to use all of the pieces together:
http://archive.dojotoolkit.org/dojo-2007-05-15/ajax/tests/undo/test_brow...
http://archive.dojotoolkit.org/dojo-2007-05-15/ajax/tests/undo/test_brow...
What usability problems?
Consider that most painful of topics for web application developers: the back button. Web developers armed with some sample code, a decent DOM reference, and a lot of perseverance can build a pretty decent dynamic UI in modern browsers. These UIs doesn't jarringly destroy the user's in-page experience for the most trivial of tasks, like adding an item to a list. When larger portions of an application are mediated in this way, the user naturally has more desire to "go back" to some earlier state if things aren't working out the way they had planned or if the action isn't what they expected. An example might be switching between a view and edit mode in a content editing application.
As high-gloss web applications become the norm, many interactions become intra-page and not inter-page. Programmers looking for creative solutions have chosen XMLHTTP for these scenarios, but unfortunately, XMLHTTP breaks the back button, impairing the user experience. If the back button doesn't function in a way that meets user expectations, it becomes ever easier for the user to lose work or become confused about the state of an application. To assist the user, programmer need a way to capture back-button presses and do something intelligent with them.
If you've used Google Maps and you've tried to send your directions to a friend, you know that not being able to simply copy the URL out of the address bar is significantly confusing at first. Applications that dynamically construct large sections of the UI (like Google Maps) today resort to a link in an intermediate screen that the user can click to return to their current state and then, perhaps, book mark or send to someone else. And this is if and when they consider the "bookmarkability" problem at all. More common is an application that simply refuses to acknowledge that the user might want to pass around a URL to a friend and instead builds some heavyweight and non-standard state serialization mechanism that is more akin to a desktop application's "save as" feature. "Save-as" on the web is book-marking, and usable applications recognize this (even if they don't have great solutions for it today). Regardless of what serialization mechanism is in use, being able to represent the state of the application in a URL (or a marker for serialized state) is a must. This is a hard problem to be sure, and none of the currently available tools provide simple answers.