I love the HTML5 History API, it makes developing applications with a consistent URL scheme across server and client super simple, however it doesn’t come without its problems.
When developing the LeviRoutes URL routing framework it became obvious that we need some changes to the specification as-is. The Mozilla documentation reports that onpopstate is called whenever the history object changes, unfortunately this is not the case, and is not the case with the spec either, the HTML5 Spec indicates: “The popstate event is fired in certain cases when navigating to a session history entry.”, which you can logically assume to be only on a forward, backwards navigation, not a replaceState or pushState.
This might sound odd. There is no mechanism to detect change in url afterit changes. You get notification via onpopstate when the user navigates forwards or backwards through your application, but not actually when it changes. This is apposed to onhashchange which does fire when the document fragment changes.
This causes us problems.
LeviRoutes listens to changes in your URL, it allows you to build applications that are responsive to the current URL, and are decoupled from navigation. So rather than have your code littered with “if(url == ”/“) { doA(); } if (url == ”/categories") { doB(); } you can now specify:
var app = routes(); app.get("/", doA); app.get("/categories", doB);
Simple right?
It would be excellent if it was that simple, but it is not. We don’t know when the URL changes via pushState. This forces us o bind our logic in our controller to call the same code that LeviRoutes would call when it detects a change in URL via normal navigation.
Now I have to bastardise my code:
var app = routes(); app.get("/", doA); app.get("/categories", doB); ..... function gotoA () { history.pushState({}, "A", /); doA(); } ...
Pretty messy right?
I would love to see an event “onstatechanged” (or perhaps, onpushstate and onreplacestate) triggered when the user pushes or replaces state on to the history object so that I can capture the code and return to my simple routing logic.
var app = routes(); app.get("/", doA); app.get("/categories", doB); function gotoA () { history.pushState({}, "A", /); }
I am not the only person asking for this: http://www.google.com/search?q=onpushstate
So, how am I going to solve this problem? I am going to wrap the History API and proxy pushState to call the natural pushState and also fire a new custom event. Hmph :\