History for Ajax pages

If you write dynamic JavaScript web pages you know about the nuisance of not having the browser managing back and forward buttons for your code. There is a number of solutions to overcome this issue, in my team we tested a few of them, than we shortlisted the candidates to history.js and backbone.js, and I think we are about to use the latter.

If you need some background on the matter, you could have a look at these pages:
Mark Pilgrim put on the web some material from his book on HTML5, here is a chapter on the history API
On Google Developers, a getting started document on Ajax crawling
On the Mozilla Developer Network, an article on Manipulating the browser history
A description of the solution provided by history.js is available on github.
Also on github you can get information on backbone.js.

The point is that we can't just rely on the HTML5 solution, the so called History API (or pushState), because we should support also clients that are using older browser. Before pushState, a few indipendent solutions were designed to tweak the fragment identifier support offered by HTML4, see this page on w3.org for details, to achieve the same result. What history.js, backbone.js, and others do is providing a way to keep the code specific to each platform localized in a place.

I am going to create a simple tiny web page with history support provided by backbone.js, and to do that I need to have at hand a couple of libraries, actually, three of them: jQuery, underscore.js, and backbone itself.

The changes to my pages are driven by three links, each of them generating an event, which should result on setting some text in a div. Admittedly, nothing fancy. But bear with me.

The HTML would be something like this:
<div id="msg">Hello backbone</div>
<hr />
<p><a href="#event/id/3">Event id 3</a></p>
<p><a href="#event/id/5">Event id 5</a></p>
<p><a href="#event/id/7">Event id 7</a></p>
The interesting part is the JavaScript code, just a couple of (dense) lines:
new (Backbone.Router.extend({ // 1
  routes: { "event/id/:id": "processEvent" }, // 2
  processEvent: function(id) { $('#msg').text('Event id ' + id); } // 3
}));

Backbone.history.start(); // 4
1. An object is created here. It is an Backbone.Router extended by the object passed, that contains two properties.
2. This routes property is used to route the event generated by the user JavaScript to what it should do. Going to the backbone router we could delegate to it the job of taking care of the history. What we say to backbone here is to get each link in the format "event/id/" plus a parameter and call a function with the name specified as value (here I've chosen the name "processEvent").
3. The name of the second property should match with the value in the object defined above (I mean, "processEvent"), and its value is the function that I want to be executed by the backbone router on my request. Here I get the div with id msg, and I set its text to a different string accordingly to the passed parameter.
4. I'm ready, so I ask backbone to start the history.

Now what happens is that clicking on the link the user changes the page content and its URL in the address bar. The browser history will work fine, and we can copy the page URL, and open it in a different browser to get the expected behavior.

No comments:

Post a Comment