This tutorial is for Dojo 1.7 and may be out of date.

Up to date tutorials are available.

Using dojo/hash

In JavaScript applications, modifying the URL hash is a great way to provide bookmarkable, history-enabled page states. With dojo/hash, adding this functionality is easy.

Getting started

When writing a JavaScript-based web site or application, it is important to ensure that standard browser controls—like back/forward buttons and bookmarks—continue to work correctly, even if the browser hasn’t navigated to an entirely new page. Using the dojo/hash module, it is possible to provide bookmarkable, history-enabled page states across all browsers.

Changing the hash

Let’s say we are creating a simple page that uses Ajax to load new content into the body of the page:


The Ajax code is loaded and executed with the <script> tag. This code updates the content and title of the page using JavaScript. It doesn’t actually change the browser’s history or the URL at all. This means that if someone bookmarks the page, or tries to navigate using the browser’s normal controls, they will find that it simply doesn’t work—there are no pages to go back to, and the bookmarked page will always start at whatever page was first loaded. With two small modifications, we can get a URL that is updated when new content is requested:


View Demo

By calling dojo/hash, the page’s URL is updated to reflect its new state, and entries are added to the browser’s history. However, when users try to use the back/forward buttons, while the URL now changes, nothing else happens. In order to make this all work, we have to add code to respond to changes to the hash. Luckily, this is just as easy.

Responding to hash changes

In order to listen for hash changes, all we need to do is subscribe to the /dojo/hashchange topic:

topic.subscribe("/dojo/hashchange", function(hash){
	loadContent(hash);
});

Now, whenever the hash of the page changes, our code will receive a notification containing the new hash value. This message is only ever published when the hash actually changes, so we don’t have to worry about getting stuck in a loop or doing a bunch of unnecessary work if the hash gets set to an identical value later. (That said, in our example, due to the circular logic between the /dojo/hashchange subscriber and the loadContent function, we store the last page requested in order to avoid making a second redundant request to the server when the hash is updated by loadContent.)

The one last thing that we need to do in order to complete state management is to ensure that we are paying attention to what the initial value of the hash is when the page loads. There are a couple of ways this can be done, but the simplest is just to call dojo/hash with the hash of the page when it first loads, if one exists:

hash(location.hash || lastPage, true);

With this code in place, the page will load, then immediately fetch the correct content for the given hash. Note that we’ve passed true as a second parameter to dojo/hash; this simply means that the new page will be replacing the current page in the browser’s history, rather than being added as a new page. This can also be useful in cases where a URL is invalidated in response to an action and needs to be removed from the user’s browser history (for instance, in a content management system, when someone deletes a record).

View Demo

Caveats

In the future, it’s likely that dojo/hash will be extended or replaced with a mechanism that supports emerging HTML features like HTML5 session history and navigation. For now, though, it operates entirely on the hash part of the URL, which means some caveats apply (though they are less severe than no state management at all).

The first and most important problem with using the hash for state management is that it creates URLs that are not indexable by search engines. If you want your content to be indexed, you must either ensure your site gracefully degrades (as our example does), or that you follow the instructions published by Google at Making AJAX Applications Crawlable.

The second, less important problem with using the hash is that it was originally intended for linking to content within a page, based on the ID of an element. If you have an element in your page with an ID matching the hash that you are using, the browser will scroll to it. In this case, prefixing your hashes to ensure they do not match any element IDs is an easy way to work around the issue. In the above example, this could be done by changing four lines:


View Demo

Conclusion

Using dojo/hash, it is easy to create applications that are highly responsive while still allowing users to interact with all of the normal browser features. A few lines of code is all it takes to add complete state management to a JavaScript-enhanced Web site or application.