I’m building a tool that uses AJAX and pushState/replaceState on top of a non-javascript fallback (http://biologos.org/resources/find). Basically, it’s a search tool that returns a list of real HTML links (clicking a link takes you out of the tool).
I am using onpopstate so the user can navigate through their query history created by pushState. This event also fires when navigating back from a real link (one NOT created with pushState but by actual browser navigation). I don’t want it to fire here.
So here’s my question: how can I tell the difference between a onpopstate event coming from a pushState history item, vs one that comes from real navigation?
I want to do something like this:
window.onpopstate = function(event){
if(event.realClick) return;
// otherwise do something
}
I’ve tried onpopstate handler – ajax back button but with no luck 🙁
Thanks in advance!
EDIT:
A problem here is the way different browsers handle the onpopstate event. Here’s what seems to be happening:
Chrome
- Fires
onpopstateon both real and virtual events - Actually re-runs javascript (so setting
loaded=falsewill actually test false) - The solution in the above link actually works!
Firefox
- Only fires
onpopstateon virtual events - Actually re-runs javascript (so setting
loaded=falsewill actually test false) - For the linked solution to actually work,
loadedneeds to be set true on page load, which breaks Chrome!
Safari
- Fires
onpopstateon both real and virtual events - Seems to NOT re-run javascript before the event (so
loadedwill be true if previously set to be true!)
Hopefully I’m just missing something…
You may be able to use history.js. It should give you an API that behaves consistently across all major platforms (though it’s possible that it does not address this specific issue; you’ll have to try it to find out).
However, in my opinion, the best way to handle this (and other related issues too) is to design your application in such a way that these issues don’t matter. Keep track of your application’s state yourself, instead of relying exclusively on the state object in the history stack.
Keep track of what page your application is currently showing. Track it in a variable — separate from
window.location. When a navigation event (including popstate) arrives, compare your knowncurrent pageto the requestednext page. Start by figuring out whether or not a page change is actually required. If so, then render the requested page, and call pushState if necessary (only call pushState for “normal” navigation — never in response to a popstate event).The same code that handles popstate, should also handle your normal navigation. As far as your application is concerned, there should be no difference (except that normal nav includes a call to pushState, while popstate-driven nav does not).
Here’s the basic idea in code (see the live example at jsBin)
If you check out the example on jsBin, you’ll see that the
_renderPagefunction is called every time the app requests a transition to a new page — whether it’s due topopstate(eg. back/fwd button), or it’s due to callinggoTo(page)(eg. a user action of some sort). It’s even called when the page first loads.Your logic, in the
_renderPagefunction can use the value ofcurrentPageto determine “where the request is coming from”. If we’re coming from an outside site thencurrentPagewill benull, otherwise, it will contain the pathname of the currently visible page.