You’re using pushState with Backbone’s history manager? I bet you’re doing something like this…
This works just fine most of the time. For browsers where pushState is available, everything works seamlessly with the URL. For browsers without pushState, again, everything works fine using the url fragment If you start sharing URLs between these two browsers, problems start cropping up and I recently came across this issue when working with the Facebook Like/Send buttons.
If you give a regular (non-fragment) URL to a browser that does not support pushState, Backbone, by itself, won’t be able to pick up on that and add the correct fragment. The same is true in the other direction as well when attempting to pass a fragment url to a modern browser. With a little bit of extra bootsrapping code, and giving up direct access to window.location, we can easily fix this problem.
We need to address both sides of this problem.
- When the application starts up
- When a URL is generated for sharing between browsers
Since pushState is the standard, and in the future will be implemented across the board, I will use the regular URL as the canonical URL. When the application starts up, we need to jump through some hoops to get Backbone.history in the right state to support the canonical URL whether or not the browser supports pushState.
First, we need to start Backbone history, with whatever option is available for pushState. We pass the silent option as true, to ensure that no route handlers will fire. Then, if pushState is unsupported, we calculate the fragment from the current window.location and navigate to that fragment. If pushState is supported, we directly trigger the route handlers.
Now, on the other side, we need to ensure that URLs that are generated from the application are the canonical URL, regardless of pushState support in the browser doing the generation. This part is simple, as Backbone has done the heavy lifting for us. We just need to concatenate together pieces of the URL that are derived from Backbone.history.
As long as we only use this function to produce a URL that is shared between browsers, our other bit of code will handle setting up the application correctly. After some find and replace, you’re application should now be able to easily handle both modern browsers, and the browsers that we just have to grit our teeth and live with.
Since implementing this, I have no longer had any further problems between browsers with and without pushState. I’ve been able to pretend that everything supports pushState within the context of my Backbone app. I don’t think that it is a very large amount of code to add to your project to get it working, and I prize simple and short solutions. I hope that some of you out there find this useful in your application. Please let me know if you have any questions on on twitterTweet