Open matteomelani opened 13 years ago
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 < reply@reply.github.com>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 rroesler@kinetekscorp.com
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:
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 rroesler@kinetekscorp.com
+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.
It was very confusing to me at first too. I fought with history.js for a couple of days trying to to make it work without changing a lot of my pre-existing code. Then I finally decided to just follow the history.js guidelines and work WITH the history.js behavior instead of trying to work around it. I changed my app logic so that nav actions only call pushState and let the statechange event handler deal with all the ajax requests and dom updates and it solved all my probs. I had also been trying to do some goofy stuff to track clicks to differentiate whether a statechange came from an actual dom element click or the forward/back buttons, but once I changed my logic to let the statechange handler take care of everything, it no longer mattered where the event originated from and I was able to get rid of my goofy click tracking code. May not be a solution for everyone, but it seems to work for me.
If I recall correctly, a big problem with this is caused when you just want to replace state data, but you aren't actually navigating. The code I had written was storing lots of random information about the page into the state data to make page transitions quicker, but it also meant that popState was being called all the time and I never knew if that was due to actual navigation or not.
I'm guessing this is done because of polling. It's an "easy way" to get rid of an inconsistency that shows up because of that, but it still makes this lib unusable in several cases.
It should just have dropped support for browsers that forced the lib to resort to polling...
very bad..... i got confused a lot .... misguided every time i see something on web related to history............. getting on my own way..
If this library really aims to follow the HTML5 History API (https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Manipulating_the_browser_history) as much as possible, then this is a bug, not by-design. Right?
+1 to change this behaviour for me also.
I basically see two obvious possibilities:
I wasted so much time debugging this, only to find this thread via a stackoverflow post. If you're not going to follow the spec, you should just say that in the README so that the rest of us can avoid your code.
if we are going into higher level using libs as we are then libs sholud wrap standards in within code and give flexibility to end user (us).
If I understand this correctly, this is mind-boggling. How can I use this thing without completely re-writing my app? Surely there is a better way?
+1 Very confusing
+1
This behavior can be worked around easily using a simple flag you store anywhere you want, but the default behavior is very confusing.
+1
+1
+1 I am working around this. But this is definitely a huge bummer.
:+1: Why is this behavior different from the spec? Why do the statechange
and popstate
events both signal for the same condition (any change of state)?
+1
I had to use a global, I check it in the statechange
event listener to see if it is being triggered a pushstate
call or not.
gPushingHistoryState = true;
History.pushState(x, y, z);
gPushingHistoryState = false;
Is there any way to tell from the statechange
event whether it was initiated by a back button or a pushstate
call?
Yep, there is an issue here. I like to get it solved in the master. In the main while you can use my version (compressed): https://github.com/danger89/history.js/blob/master/scripts/bundled/html5/jquery.history.js
And uncompressed: https://github.com/danger89/history.js/blob/master/scripts/bundled-uncompressed/html5/jquery.history.js
It's still not fixed. See also: https://github.com/browserstate/history.js/issues/47
The solution:
(function(history){
var pushState = history.pushState;
history.pushState = function(state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({state: state});
}
// ... whatever else you want to do
// maybe call onhashchange e.handler
return pushState.apply(history, arguments);
}
})(window.history);
from: http://felix-kling.de/blog/2011/01/06/how-to-detect-history-pushstate/
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!