22 Feb 2011

I’m not sure if it’s the immaturity of the browser support or my general uselessness but I’ve been having some trouble with the JavaScript history API.

I won’t try to explain the history API here, it’s pretty well covered at Mozilla Developer Network and W3. The basics are simple enough:

The API provides two methods; pushState which allows you to add a new entry to the browser history and replaceState which modifies the current history entry.

New entries added to history using pushState can be navigated via the browser’s back and forward buttons and a popstate event is fired on the window object when this happens.

Both methods allow you to attach arbitrary data to the history entry that you can use to reconstruct the appropriate page state when the user uses the back or forward buttons.

I imagine a pretty typical use-case is what I’ve been trying to do with the pagination and sorting on the list pages of Grails scaffolding. Instead of pagination links and column headers causing a full page reload when clicked I intercept the click event and send an AJAX request getting back a page fragment I can use to update the list in the page. Easy enough, however without the history API it will break the back and forward buttons and make deep linking impossible. This isn’t an acceptable option so in true progressive enhancement style I’ve used Modernizr and only apply the AJAX behaviour if the browser supports the history API.

The essence of the script involved is this:

var links = //... pagination and sorting links
var container = //... the region of the page that will be updated with AJAX
// override clicks on the links
links.live('click', function() {
// grab the link's URL
var url = $(this).attr('href');
// add a new history entry
history.pushState({ path: url }, '', url);
// load the page fragment into the container with AJAX
container.load(url);
// prevent the link click bubbling
return false;
});
// handle the back and forward buttons
$(window).bind('popstate', function(event) {
// if the event has our history data on it, load the page fragment with AJAX
var state = event.originalEvent.state;
if (state) {
container.load(state.path);
}
});
// when the page first loads update the history entry with the URL
// needed to recreate the 'first' page with AJAX
history.replaceState({ path: window.location.href }, '');

At first glance this works pretty nicely. In browsers that support history (right now that’s just Chrome, Safari and its mobile variants) paginating and sorting the list does not refresh the entire page but the browser’s location bar is updated so copy-pasting or bookmarking the URL will give a valid link to the current page. What’s more, the back and forward buttons can be used to step back through the list pages just as if we reloaded the whole page. In non-history-compliant browsers the list page behaves just like it always did; the links reload the entire page.

Unfortunately there’s a problem that was reported to me on GitHub shortly after I uploaded a demo of my scaffolding work. Where everything falls down is when you paginate the list, follow a link off the page (or just use a bookmark or type in a URL), then use the back button to return to it. In Chrome and iPad/iPhone variants of Safari the browser displays just the page fragment from the last AJAX call, losing all the surrounding page along with styling, scripts, etc.

Where things get very odd is that adding a Cache-Control: no-cache header to the AJAX responses makes the problem disappear, presumably because the browser then doesn’t cache the AJAX response and has to use the historical URL to reload the entire page. Remember, in good progressive enhancement style the URL for the full page or the fragment is the same. The server uses the X-Requested-With header to decide whether to return a fragment or the whole page. Obviously, forgoing caching is hardly an acceptable compromise but it’s interesting in that it reveals what the browser is doing. It can’t, surely, be right for the browser to treat a page fragment the same as a full document!

Curiously in desktop Safari this doesn’t happen and the full page is loaded as you would hope. Looking at the User-Agent header it looks like Safari is using an older version of WebKit (533.19.4 rather than 534.13).

You can see the behaviour in my scaffolding sample app. I also ran into the exact same issue today at work whilst trying to add history navigation to this page (which is a good example of why you’d want to use history in the first place). I don’t think it’s just me, either. The same problem can be seen with the demo linked from this post about the history API.

If there are any JavaScript experts out there who can point out my obvious incompetence here, that would be great. Otherwise I guess I’ll have to wait for updates to WebKit to hopefully fix the issue before I can start applying this technique with confidence.

524 comments:

I couldn't see the issue you mentioned in when trying your site in chrome, when going back after leaving the site I get taken back to the page with the sort order as it was.

Assuming that your server is also capable of rendering the table, for those browsers that don't support pushState, the server should probably handle those kind of requests, and once the page is loaded the JavaScript can take over.

I have a nice library that wraps pushState to provide this kind of routing, Davis.js it might be worth a look if you end up using this technique some more.

I encountered the same problem. Clicking a link to go to another page then hitting Back causes the browser to display the json response rather than the previous page.

History.js doesn't fix it. I switched to it hoping it would, but nothing changed. The Cache-control header fixed it, though. I had to use a value of "no-cache no-store" because just using "no-cache" didn't help. This is on Firefox 6.0.1.

I use history.js and I had the same problem and afaik there is no solution until browsers themselves process pushState history differently. Like you, I don't like suppressing page caching, so I decided to render full pages via ajax and pull out the necessary information. Luckily my framework and site layout made this simple. Yes, it make the ajax request larger, but at least they're cached in their fullness. For now, this is the best solution for me.

I found found that adding a query param to the url (e.g. "ajax=1"), when called via ajax, solved the problem. This way, the browser does not mix it up and page fragments loaded by Ajax still get cached.

I just wanted to thank you for sharing this wonderful baking. The effects generated by Javascript can be downloaded much faster than some other technologies such as Flash and Java applets. In fact, unless you write a JavaScript application is too large, and almost all common JavaScript code does not significantly increase the download time of web pages. The duug nor download the plug-in components before they can view the content they have done Javascript as with Flash, they just need a browser with Javascript support - and of course, the majority of current browsers support Javascript.!G9G , Dora , Kizi new , Huz 2 , Kizi hot , Friv 4 , 85 Play , 4223 Games , 85 Games

I am very happy to read this. Appreciate your sharingRed Ball is a online, platform games series, posted by King. It involves a red ball 4 stuck in a world of various levels, and hola launcher is a freemium web and mobile application which claims to provide a faster, private and more secure Internet. Whether you are looking to improve your culinary skills or you simply love whipping up tasty treats, this simulation game named cooking fever will surely leave your mouth watering. Sun, sand, surf, and all the fish you can eat! Sail away to paradise bay, where you'll help Keani and friends restore the island to its former glory. The and, agario is a fun addicting MMO game in which you have to eat or be eaten while you strive to dominate the World of colorful cells Good happy !

Great stuff. This is really a fascinating blog, lots of stuff that I can Get into. One thing I just want to say is that your Blog is so perfect!Swords And Souls is a fighting game developed by Soul game studio. You play as a warrior whom you have to train into a hero in a Roman ancient town. And, subway surfers is an "endless running" mobile game co-developed by Kiloo, a private company based in Denmark and SYBO Games. It is available on Android, iOS, Kindle, and Windows Phone platforms. Play goodgame big farm games online for free, the best online farm games by Goodgame. You can also eject extra mass and split into multiple parts to outplay smaller cells. The end, ninjago games is a popular ninja games developed from Lego Ninjago brand. The game attracted the interest of millions kids with a gripping storyline and new sections are constantly being updated. To play agario click here to move the cell using the mouse, to divide into equal cells. If you collide with a smaller cell, you will absorb it and grow. Good lucky!

I wanted to thank you for this excellent read!! I definitely loved every little bit of it.Cheers for the info!!!! & This is the perfect blog for anyone who wants to know about this topic. I like Score Hero, camera b612, papas games, Piano Tiles 2, Dream League Soccer. Papas Games is really something, none of the series are cliché and all of them are very much enjoyable.

I just wanted to say thank you for sharing a great information and useful. it really necessary and timely for me at this time. I've read a lot of blogs and visit but they made me feel boring. Your article made me feel strange and fascinating it attracted me. I wanted to share this information with my friends on the social network facebook.!G9G , Dora Games , Kizi new , Huz Games , Kizi hot , Friv 4 School , 85 Play , 4223 Games , 85 Games

Hello my friend! I want to say that this post is awesome, great written and include almost allimportant infos.I really love this post I will visit again to read your post in a very short time and I hope you will make more posts like this.

When you're tired, you want to relax after a stressful working hours, you need to have time to take care of the kids active. Please visit our website and play exciting flash games.Thanks you for sharing!Friv 4

Welcomes to google underwater keep sharing such ideas in the future as well. google mirror this was actually what i was looking for,and i am glad to came here! elgoog Hi! I’ve been reading your blog for a while google gravity I want you to thank for your time of this wonderful read!!! google terminal now and finally got the courage to go ahead and give youu a shout out from Austin Texas!google pacman Just wanted to tell you keep up the fantastic work!my weblog: google guitar I definately enjoy every little bit of it and I have you bookmarked to check out new stuff of your blog a must read blog! google snakeAmazing insight you have on this, Happy wheels it's nice to find a website that details so much information about different artists... Age of war 2 This article always blew me... Earn to die For how many times I have read this.slither ioslitheriobig farm

This is the best application on the drop today. There access to enjoy great moments of relaxation . Great! Thanks for sharing the information.Summon creatures to fight enemy units and demolish the opposing castle. Your castle is equipped with a crossbow, which you can use to shoot enemies . Make sure you upgrade skills to increase your chances of winning battles.: age of war 2 | age of war 5 | age of war 6 | age of war 4

First of all i am saying that i like your post very much.I am really impressed by the way in which you presented the content and also the structure of the post. Hope you can gave us more posts like this and i really appreciate your hardwork.

Most of peoples are looking for the Sarkari Naukri and one of the major question is How to find it.? Maharashtra government recently launched the one protal named Maharojgar and they are helping Studnets for searching there jobs. They are giving Employment Cards to everyone. Just do the Employment Card Online Registration on official website.

To flee war, Kizi | Yoob to protect the lives of themselves and their families, and must live with the rhythm of society, sometimes makes people feel comfortable smell. Be strong in the harshness of life, you will succeed. Friv | Doraemon Games

Facebook has become a part of my life, not only helped me to connect with you nè but also where I can share every moment in life. I really like the convenience that it brings[url="https://plus.google.com/u/0/104108011489995969586/"]facebook baixar[/url] , [url="https://twitter.com/facebookgratis5"]facebook baixar[/url] , [url="https://baixarfacebookgratis.wordpress.com/"]facebook baixar[/url] , [url="https://sites.google.com/site/baixarfacebookgratis01/"]facebook baixar[/url] , [url="https://www.pinterest.com/facebookgratis5/"]facebook baixar[/url] , [url="https://www.flickr.com/photos/baixarfacebookgratis/"]facebook baixar[/url] , [url="http://imgfave.com/baixarfacebookgratis"]facebook baixar[/url] , [url="http://baixarfacebookgratis.deviantart.com/"]facebook baixar[/url] , [url="http://baixarwhatsappgratis02.weebly.com/"]facebook baixar[/url] , [url="https://myspace.com/baixarfacebookgratis"]facebook baixar[/url]

I was noticing from many days that your blog is helping too many readers as your articles are easy to understand and helpful to us.I think you should explore the articles on your website, You should also cover different different categories for articles as you writes awesome. Thanks for sharing this great article with us.

Life becomes more interesting and wonderful when you share your memorable moments with friends and family through unique photographs. You can create your own unique style impressed with image editing software.square quick , download square quick , square quick app

In the afternoon I go play ball, took off her jacket to give you that, you stood on the edge of the field, taking clothes, naturally folded it neatly and then hugged to his chest, then smiled stood there cheering for merun 2 , run 2 game , play run 2 , run 2 unblocked , run

Diwali, or Dipawali, is india’s biggest and most important holiday of the year. The festival gets its name from the row (avali)of clay lamps (deepa) that Indians light outside their homes to symbolize the inner light that protects us from spiritual darkness. This festival is as important to Hindus as the Christmas holiday is to Christians.