window.onhashchange, jQuery hashchange, history.pushState and History.js

If you wish to make your AJAX website bookmark and back button friendly, you will need to use location.hash or history.pushState. Below are some short examples of how it all works.

1. Before HTML5, we needed to use onhashchange. Here’s an example of how this works. Notice we start the hash with a “!” to enable Google AJAX crawling.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script>
		$(function() {
			window.onhashchange = function () {
				alert("onhashchange = " + window.location.hash); // do something on click
			}

			alert("onload = " + window.location.hash); // do something onload

			$('#link').click(function(e) {
				e.preventDefault();
				window.location.hash = '!hello';
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

2. If you would like a jQuery solution, you can use the jQuery hashchange plugin.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script src="http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js"></script>
	<script>
		$(function() {
			$(window).hashchange(function() {
				alert("hashchange = " + window.location.hash); // do something on hashchange
			})

			$(window).hashchange(); // force hashchange onload

			$('#link').click(function(e) {
				e.preventDefault();
				window.location.hash = '!hello';
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

3. HTML5 introduced history.pushState, which allows you to change URLs without using hashes.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script>
		$(function() {
			window.onpopstate = function() {
				alert("onpopstate = " + window.location.href); // do something onpopstate
			};

			alert("onload = " + window.location.href); // do something on load

			$('#link').click(function(e) {
				e.preventDefault();
				history.pushState(null, null, 'hello.html');
				alert("pushState = " + window.location.href); // do something on click
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

Don’t try this by opening a local HTML, where you see file:// in the browser URL, or you might get some security issues. The onload alert is needed on Firefox, but is redundant in Chrome and Safari.

4. If you would like a solution that will use history.pushState for modern browsers but fallback to onhashchange if history.pushState is not supported, try History.js. Make sure you first download and make jquery.history.js available, and don’t test this on a URL that starts with file://.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script src="history.js/scripts/bundled/html4%2Bhtml5/jquery.history.js"></script>
	<script>
		$(function() {
			window.History.Adapter.bind(window, 'statechange', function() {
				alert("statechange = " + window.location.href); // do something on statechange
			});

			alert("load = " + window.location.href); // do something on load

			$('#link').click(function(e) {
				e.preventDefault();
				window.History.pushState(null, null, 'hello.html');
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

Now you got a glimpse of how these work, I suggest you read Must-Know URL Hash Techniques for AJAX Applications, which gives an overview of the whole workflow.


4 Comments

  1. shawnmaddock says:

    Could you elaborate on why the onload alert is needed in Firefox? Is there a bug in the browser that prevents state events from firing unless an alert box is loaded? That seems pretty debilitating.

  2. The Mozilla Developer Network says “Browsers tend to handle the popstate event differently on page load. Chrome and Safari always emit a popstate event on page load, but Firefox doesn’t.” So if you want to do some action on page load, you need to trigger this explicitly on Firefox.

  3. The history.js example is what I was looking for. I am now trying to get an event to fire on click of the forward and back buttons to restore my content.

  4. miguel says:

    This works great on Mobile Safari on iOS 5. I was having the issue of Safari not registering the back hash tag so this is a great alternative! Thank you!


Leave a Reply

Your email address will not be published. Required fields are marked *