history.js
history.js copied to clipboard
statechage is triggered everytime pushState is called
Probably I am just very confused....
so in Firefox 6.0.1 everytime I call pushState the statechange event get fired. Is this the expected behavior?
How do you go about restoring the state of your page?
For example let's say I have page users/1/post_board, the page presents to the user a list of posts. Now the user can simply filter the post by clicking a button. The button does an ajax call to /users/1/post_board?author=john. The app javascript invokes History.pushState() with a state object that contains all the info so that when the statechage event is triggered the page can be rebuilded. But since pushState trigger a statechage the page gets built twice.
What am I missing here? Do you have any example of how this should work? I am sorry to say but the demo is pretty useless since there is not state rebuilding in it.
Thanks!
Can't you just get the button to do the History.pushState() and then get the statechange event to manipulate the page content? I'm pretty sure that's how it's intended – and this way when the user clicks back/forward the statechange event will fire and manipulate the page content.
Hope that makes sense.
yes that is what I ended up doing.
-Matteo
On Thu, Sep 15, 2011 at 12:22 AM, Jason Berry < [email protected]>wrote:
Can't you just get the button to do the History.pushState() and then get the statechange event to manipulate the page content? I'm pretty sure that's how it's intended – and this way when the user clicks back/forward the statechange event will fire and manipulate the page content.
Reply to this email directly or view it on GitHub: https://github.com/balupton/history.js/issues/96#issuecomment-2101733
-Matteo
I have to second matteomelani's confusion.
Why does calling History.pushState() (or .replaceState()) trigger a 'popstate' event?
The "native" history.pushState() does not do this.
The 'popstate' is handled in History.onPopState, which then triggers a 'statechange' Event (line 1681, v 1.7.1).
I just want to push ... not have the thing popped right back at me.
Confusion here too. Sometimes I it's quite pratical to differentiate between pushing and poping a state.
The documentation, the example, to reference to Ajaxify, all make it clear that statechange gets call on every state change. And the promoted pattern is to change your code to actions call pushstate which causes a statechange which (should) invoke the actual action.
But, wow, does this cause a lot of extra effort when authoring the solution.
I'm using unobtrusive Ajax and my links of tons of data-* attributes to drive the actual partial page refresh, highlight menu entries, run back ground actions (initializations, "welcome popups"), etc.
With History.js I have ended up with a lot of duplicated actions, A user visible action that calls pushState and a hidden action that does the actual work. I also ended up almost duplication the state so that I could handle back/forward vs new action properly.
And my stateChanged event handler has become very complex as I attempt to match states to the hidden actions.
At least one whole layer of this could go away if stateChange told me whether the change was a back/forward button push or a pushState/replaceState/original navigational. Things which the code is doing now in its popState event handler.
I'm currently in optimization mode, and looking to possible replace History.js (or modify it) so the application code can be simplified into something that someone else might be able to follow.
I modify my copy to better match W3C popState event semantics (I think) .. we are testing in our application now.
See issue 137
@rroesler can u share your version
Can you read branch/fork "rroesler / history.js" .. I updated my change this morning.
Otherwise email me at [email protected]
By all means, provide an event that triggers whenever pushState() is called, to allow for the current workflow.
However, there should also be an event that reacts only to actual browser navigation. There is a reason the spec was designed as it is. Forcing the actual content load to be done through the statechange event is a flawed approach, and makes all kinds of things more complicated.
The fix by @rroesler may be the wrong solution to this. It supresses the statechange event, but popstate is still artificially triggered. Instead, maybe continue to trigger statechange on pushState(), and let popstate only trigger when there is an actual pop taking place.
I also can't understand History.js behavior. All provided samples are pretty useless.
History.js give us two events: popstate and statechange. popstate is from History API spec - https://developer.mozilla.org/en/DOM/window.onpopstate. But why do we need statechange event? Anyway both events fire in the same conditions: when any change happens.
But obviously any app has two workflows:
- when an app changes its state and just wants to track this change in the history
- when a user change app's state via back/forward or direct url navigation
These cases should not be treated in the same way as it now happens.
UPDATE: HTML spec doesn't state that popstate event should be raised on pushState: http://www.whatwg.org/specs/web-apps/current-work/#history-0 Also not firing popstate event on call History.pushState method is expected by many people - see http://diveintohtml5.info/history.html
Confused++
Specification [1] [2] states that: "just calling history.pushState() or history.replaceState() won't trigger a popstate event".
History.js aims to "overcome the cross-browser compatibility", and it's been doing a great job. Sometimes, it's hard to strictly follow the specs. But, in my opinion this issue is a core behavior for the history manipulation. Going against the specs here should not be a by-design thing. One possible solution would be having an event (a) to behave the way popstate should, and having an event (b) to behave the currently-always-triggered-way.
I strongly encourage History.js to re-think about it.
Anyone have a fork of history.js designed more in alignment with the w3c spec?
First, thanks for building and sharing History.js.
I don't really have much to add to this discussion, but I wanted to add a +1 for not firing popstate on pushState/replaceState.
Unfortunately, History.js, while laudable, is useless for me because of this behavior. See here for a little more about why.
I also want to request the same - I came to History.js to support IE9 back button support (I'm using popstate)
+1 for not firing popstate on pushState/replaceState please!
+I third this.
To handle this flow, I have to wait for the pushstate event to fire before I can follow through with application logic. Waiting for this event makes things harder to follow and more importantly goes against the W3C spec.
This shouldn't be called a shim for the HTML5 History spec, if by design it isn't following the spec. Since most likely this has become the norm for people who have implemented History.js I suggest a conditional option that isn't by default set.
generally +1 to the discussion here.
To me, W3C Spec whatever is just a preferable thing, it's better working. And in order to avoid this issue, I need to make a big work around. If you can just pass me one flag in statechange event, that can distinguish the event from pushState()/replaceState() call, that's helps me out A LOT.
+1
+1
There's a reason why History.js is using the same function names as the HTML5 history API (pushState(), replaceState(), and onPopState()). It's because they're intended to work like the HTML5 history API (save for the capital "H" on the "History" variable, but that's pretty much necessary). In fact, the description of the project clearly states that "History.js gracefully supports the HTML5 History/State APIs (pushState, replaceState, onPopState) in all browsers."
The HTML5 history API specification clearly states that pushState() and replaceState() should not trigger a popState event.
Either make History.js act like the HTML5 history API or stop claiming that it does, because it doesn't.
rroesler's pull request ( https://github.com/balupton/history.js/pull/137 ) fixes only the HTML5 version. history.html4.js still has the same issue, which means that HTML4 browsers which don't support the HTML5 history API experience this bug (yes, it's a bug) even with rroesler's pull request applied. So, there is still work left to do, but rroesler's pull request goes a long way.
(I would have created an issue on rroesler's fork, but there's no "issues" tab at the top. I'm fairly new to github's workings, so I'm uncertain why that is, exactly.)
Anyway, in summary, this is a bug and it should be fixed. If the current behavior is by design, then it is still a bug -- a documentation bug.
+1
I spent a few hours to figure out why popstate event gets fired on pushState. This is not, to me, an intuitive behavior.
Thanks for all the great work you've done anyway, Cheers!
Finally got around to looking deeper into this. I believe I have a fix for this issue in HTML4 browsers. I'm going to do some more testing and commit it to my fork ( https://github.com/AntiMS/history.js ) of rroesler's fork probably some time tomorrow evening. (My time zone, of course. In around 24 to 30 hours from now).
Sorry guys, on Git Hub, under Admin, you can enable Issues, since this was my first action on GitHub, did not know this. Enabled now for the future.
I can see the bug now. For some reason this never affected my own application. If you have need assistance, you can get me at [email protected]
+1
Heh. 11 days later. :P
Something came up, I'm afraid.
By the way, can anyone here suggest a decent browser on which to test the HTML4 functionality on a GNU/Linux system? (Hopefully something that won't take hours to build, either.)
+1
+1
+1
+1 my current ajax library called phery, have issues with double firing on Chrome, and I'm having to use popstate instead of the artificial statechange, because my library calls the remote address when clicking on the link, and not when the URL changes. Back button also works once, getState() returns only one step back in history
I guess we can use https://github.com/devote/HTML5-History-API
+1 on the confusion. It would be very helpful to have the author weigh in on why he designed it this way, along with pros and cons. Balupton is very active answering questions and promoting history.js, so i'm sure he has seen this thread. More information would be really helpful here... Perhaps a switch to toggle whether pushstate fires a statechange event?
This behavior is very confusing to me as well.