can window.onPopState() event handler know direction of navigation? (forward,backward) - javascript

i have a site that uses ajax navigation with the pushState() method and an onpopstate() handler.
when first visiting the main page, i display a default content (without ajax).
when someone navigates away from the default page and then goes "back," a null state is supplied when they should be returning to the default page. thus, they stay on the second page of the website instead of the first ( although the handler can easily use ajax to bring the initial content back).
my only way to fix this was to do a pushState on my initial page load with information on what the initial content is. with this method, the "back" button works great!
BUT if someone was at www.stackoverflow.com before going to my site, the goes "back" to stackoverflow and then "forward" to my site again, the initial content is shown, but then reloaded again because the "popped" state is not null.
so can i tell, in the onPopState() handler, whether the user is going backward or forward?

I've had some success with using the pageshow event in Firefox to trap that initial entry into the site through forward and back buttons.

can window.onPopState() event handler know direction of navigation? (forward,backward)
There is an issue. You can skip states (hold the back button, select the state you want). This makes it incredibly hard.
when someone navigates away from the default page and then goes "back," a null state is supplied when they should be returning to the default page. thus, they stay on the second page of the website instead of the first ( although the handler can easily use ajax to bring the initial content back).
You can fix that with History.js with it's optional data persistance.

Related

Prevent the URL from changing when popstate occurs

Hi I'm trying to implement a "Are you sure you want to leave this page?" popup when navigating away from a page with a modified form that hasn't been submitted. The website is a single page app built using a custom framework.
Since all anchor links are handled by the framework it can tell that clicking a side nav link will cause a page change and show a Bootstrap confirm dialog. If the user clicks "Ok" the click goes through and an AJAX call is made to pull the new page content. If they click "Cancel" the modal is dismissed and they stay on the current page.
The part I haven't been able to solve is when a user clicks the "Back" button in their web browser. This triggers the "popstate" event. All navigation/history is managed using the history API since it's a single page app.
The issue is that when someone clicks "Back", the URL changes since "popstate" occurred, then I show my "Are you sure you want to leave?" modal. When the event occurs the URL in your address bar now shows the page you would go to from your history, not the page you're currently viewing. If you click "Cancel" in the Bootstrap confirm you are now left with the wrong URL displayed in your address bar.
event.preventDefault, event.stopPropagation, or return false inside popstate don't stop the URL from changing. AFAIK you can't intercept the "Back" button before "popstate". Trying to window.history.replaceState inside "popstate" doesn't seem to work either.
Does anyone have a solution on how to make this work?
Can you stop the URL from changing in the "popstate" event?
Can you rewrite the history somehow in "popstate" to change the URL back to what it was on the current page and retain the previous entry if you do decide you want it to go through after a modal has been accepted?
Some other solution I haven't thought of?
My original thought was to block the URL change in "popstate" then let the framework trigger the link click to load the new content and change the URL if they click "Yes" but I haven't found a way to do that.
Thanks!
I solved this by doing the following;
Each time a history state is created I generate a timestamp as a guid
The current timestamp is stored in a variable on the top level module
When popstate occurs the incoming history state's guid is compared against the top level modules guid
If the new guid is greater we're going forward, if it's less we're going backward
When the user clicks the back/forward button the hash does change to the incomming URL. If the user clicks cancel it runs history.go( direction ) where direction is 1 or -1 depending on the timestamps. This sets the URL back to what it should be and doesn't do anything weird to the history stack. The top level history variable has a flag to know that we're faking a page change so the link load logic in popstate is not executed.
The only quirk is if the user does click yes to navigate away when that request is sent and returned and a history object is created you do not update the top level module's guid. If you do the guid comparison will always think you're going backward because the new event you just added will always be the highest number. This may not be an issue if you don't make new requests for history URL's but our framework does so it doesn't display stale data like the browser typically does.
It's not ideal since you do see the URL change (no content changes) but so far it seems to work well enough. Another solution I found was to store your own site's history in local/session storage and compare URLs instead of using guid timestamps to find the popstate direction. This won't work in Safari's private browsing mode since both storage layers are disabled so I opted for guid's.

How to trap the back button and refresh the page using ajax

I have a web page which updates progressivly therefore I need the windows "back" button to call a function to refresh the data and not go back a page.
I have the first part working I trap the "back" button with
window.onbeforeunload = confirmExit();
and confirmExit()
function confirmExit() {
switch (page) {
case 2:
countries();
break;
case 3:
counties(page3id)
break;
case 4:
cities(page4id)
break;
}
}
Which all works well but after the page is refreshed the back button default action kicks in and it loads the previous page. I have tried returning true and false. I would appreciate any help, thank you.
you need to add virtual sites to the browsers history. this way the back button will not lead to another website.
use history.pushState() to add virtual sites.
Suppose http://mozilla.org/foo.html executes the following JavaScript:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
This will cause the URL bar to display
http://mozilla.org/bar.html, but won't cause the browser to load
bar.html or even check that bar.html exists.
Suppose now that the user now navigates to http://google.com, then
clicks back. At this point, the URL bar will display
http://mozilla.org/bar.html, and the page will get a popstate event
whose state object contains a copy of stateObj. The page itself will
look like foo.html, although the page might modify its contents during
the popstate event.
If we click back again, the URL will change to
http://mozilla.org/foo.html, and the document will get another
popstate event, this time with a null state object. Here too, going
back doesn't change the document's contents from what they were in the
previous step, although the document might update its contents
manually upon receiving the popstate event.
from MDN: Manipulating the browser history
the user can now press the back button the number of times you added virtual sites. to detect the back button press use window.onpopstate
The popstate event
A popstate event is dispatched to the window every time the active
history entry changes. If the history entry being activated was
created by a call to pushState or affected by a call to replaceState,
the popstate event's state property contains a copy of the history
entry's state object.
from MDN: Manipulating the browser history

What's window.onunload?

Im a beginner and i see that line of code a lot on javascript files , for example :
window.onunload=function(){};
when should i use this and what is it role exactly ?
thank you .
This function gets called when the user closes the browser or navigates away from the page.
https://developer.mozilla.org/en/DOM/window.onunload
You also might want to check out onbeforeunload, which allows you to prompt the user with a confirmation message before leaving the page. This can be useful for reminding the user to save their changes, or making sure the user doesn't actually want to claim their free iPad 2.
onunload is an event that is triggered when the user navigates away from your page, or when the page is "unloaded".
It's triggered when a user follows a link, or closes the tab. It's used for clean up. Like saving a user's data when they leave the page. Usually it's paired with onbeforeunload (which is called before onunload is using the same criteria) to warn a user that they have unsaved data.
if a page has an onunload handler, browsers that restore the page state (remembering changed form field values, script environment) when you navigate away and back to the page do not-
that is, they load the page as if it was the first time it was opened, with no user applied changes.

When the back button triggers popState how can I prevent a page refresh?

I am trying to modify the content in my page without a reload. Currently my code reads:
window.onpopstate = function(event){
// Ajax Request the Page and replace content with new content
};
This works when I push a state then trigger the popstate event, but if I press the back button in the browser it navigates to the url instead of calling my onpopstate event. How can I prevent a page refresh and update the page with my ajax call instead?
edit: I am trying to update with pushState and popstate. I was hoping to keep my urls hash free.
You have to make sure there is always a history state you've pushed from the current page on the history to prevent the back button from performing a page load.
If you're trying to keep the user "contained" in your web app so the back button always provides some kind of function, you need to push at least two states onto the stack and then make sure to push another state from your popstate handler.
var foo = {foo: true}; // state object
history.pushState(foo, "unused argument", "#newInitialUri");
...
var bar = {bar: true}
history.pushState(bar, "unused argument", "#newStateOfWebApp");
...
window.onpopstate = function(event){
...
var baz = {baz: true}
history.pushState(baz, "unused argument", "#baseState");
};
In the above example say we loaded '/'. The script starts executing and the browser window URI changes to '/#newInitialUri' but no page load occurs. Then immediately after, the browser URI changes to '/#newStateOfWebApp' and no page load occurs.
The user pushes the back button on their browser. Your popstate handler fires. During your handler, event.state equals foo and the browser uri is '/#newInitialUri'. No page load occurs. The handler finishes completing, calling history.pushState and now the browser uri is '/#baseState'. No page load occurs. If the user clicks back again, your popstate event will fire again, event.state will equal foo (again), the browser uri will be '/#newInitialUri' (no page load) and then it will be '/#baseState' again (no page load).
The important thing to remember is that the event.state in your popstate handler always contains the state object for the URI you've just come back to, not the one you just came from. This was confusing to me at first, but made sense when I thought about it. For example, the user may have just come back to your page after perhaps having gone off to Google. The state object is your opportunity to communicate the status of your app to your code.
Keep in mind that some browsers fire the popstate event on page load (which is what's supposed to happen according to the spec from my understanding). Be sure to check for your state object in your handler before executing your code to make sure you don't run code you don't intend to on a page load.
One final note: if you're using jQuery to handle events, you'll need to use event.originalEvent.state to refer to the state object.
This may help
The unload event is sent to the window element when the user navigates away from the page. This could mean one of many things. The user could have clicked on a link to leave the page, or typed in a new URL in the address bar. The forward and back buttons will trigger the event. Closing the browser window will cause the event to be triggered. Even a page reload will first create an unload event.
Reference
http://api.jquery.com/unload/
untested
$(window).unload(function(e){
e.preventDefault();
$(window).trigger('popstate ');
});
$(window).bind('popstate ',function(){
//your ajax call here
});
and finally here is a DEMO click on browser's back button to see it working
update
you are right the unload be canceled but you can do some thing like
$(window).unload(function(e){
e.preventDefault();
$(window).trigger('beforeunload');
});
$(window).bind('beforeunload',function(){
alert('call your ajax here');
return '';
});
yet another DEMO

How can I get reason of page unloading in javascript's onunload event, in IE?

There may be different reasons of page unloading:
1 User closes the current window.
2 User navigates to another location.
3 Clicks the Back, Forward, Refresh, or Home button.
4 User submits a form, and then browser starts to unload current page and load page with results of form submitting. (Assuming that the current window is the form's target).
5 and so on...
Can I somehow know in onunload handler that the reason of unloading is p.4, i.e. moving to page with results of form submitting?
I could define some flag when submiting form, but this does not solve the problem. Because response (on form submit) from web server takes some time, browser doesn't unload the current page immediately and waits response from server. And during this waiting user may close window or navigate anywhere. And I need to know whether was it indeed moving to results page or something else...?
You could hijack some of those events.
For example for links, you could add an event handler on links that saves their href attribute, performs what you require, then sets window.location to the href you had stored in a variable.
The exact reason of page unload cannot be known in the unload handler. OnUnload event is not a standard and was implemented by IE first.
Different browsers might handle it differently and fire the event for different cases.
msdn reference
mozilla reference
So if you are trying to know the reason of unload in the unload handler, I think you might be out of luck. However as Alex pointed out in his answer, you could probably know about user navigating away from your page by clicking some link on your page by making your click handlers for those links more intelligent.
on unload cant handle its looks like but maybe when load you can handle.
as explained
performance.getEntriesByType("navigation")[0].type
You can check this Link
What is the replacement for performance.navigation.type in angular?

Categories