I want to post an message to the server when user navigate off from the current page, I am using .unload right now but the result is unreliable, even in its document is said true:
The exact handling of the unload event
has varied from version to version of
browsers. For example, some versions
of Firefox trigger the event when a
link is followed, but not when the
window is closed. In practical usage,
behavior should be tested on all
supported browsers, and contrasted
with the proprietary beforeunload
event.
Should I use beforeunload event? Is it reliable?
Yes, beforeunload is more reliable, but be sure to assign it directly (not bound through jQuery), like this:
window.onbeforeunload = function() { /* do stuff */ };
The unload event itself wasn't meant for work to be done, only cleanup of objects...as garbage collectors get better and better, there's less reason for the browser to even fire the unload event.
Also be aware that for your specific case you'd have to make a synchronous request to the server...otherwise the browser still won't wait for the AJAX call to complete.
Related
I want to make sure the user gets a warning when closing the window on some occasions (unsaved data, for example). Works well.
BUT: I also need to do some clean up work BEFORE the window closes but AFTER I asked whether the user really wants to close it.
So I have two callback functions, one for onbeforeunload that will throw the confirmation dialog, and one for onunload that should do the cleanup.
Unfortunately, in Safari, the onunload callback does not seem to be called.
Why?
$(window).on('beforeunload',function() {
if (connected)
return "Are you sure you want to close the window!";
});
$(window).on('unload',function() {
localStorage.removeItem("someItem"); // never executed in Safari
});
Unfortunately, this event is not supported in some of the browsers. You can try using pagehide event instead of onunload.
Good Luck!
So this is really bugging me, I don't know if it is a browser related glitch or javascript just works that way ( I hope it does). I created a fiddle. https://jsbin.com/laluziqede/1/edit?html,js,output
Open your console, then click the button. When the dialog appears the function continues normally (first console.log isn't paused), however the one inside setTimeout function is paused and will only show after you click 'stay on page'.
But why, could someone explain this? I want to use this property in my application (execute an action right after user clicks stay), but I'm not sure if it's a good practice and is it working on all browsers and devices.
Edit: Here's the code from the bin:
$(window).on('beforeunload', function() {
return 'Check your console please and then click stay';
});
$('#click-me').on('click', function() {
window.location.href='about:blank';
console.log ('dialog won\'t stop me from showing');
var timer=setTimeout(function() {
console.log('this was paused by the dialog');
},0);
});
The behaviour is browser dependent. I tested it in Firefox, Chrome, IE and Edge, and of those only Chrome has the behaviour that you describe.
The difference lies either in when the beforeunload event is triggered, or when it is handled. Most browsers trigger the event immediately when you change the location property and also handle it immediately. Chrome either triggers and handles the event when the navigation is actually about to happen, or places the event on the queue and handles it later just like regular events.
In Chrome the code inside the setTimeout handler will not happen until after the beforeunload event is handled, either because the navigation is handled before any queued events, or because the timout event is after the unload event in the queue.
Javascript is single threaded (unless you start using things like WebWorkers and other newer technologies). So the timer function schedules something to be done, but it will only be done when everything else has yielded control of the javascript thread. So timer is only asynchronous in the sense that you're asking for some work to be done after some period of time, but it is not truely asynchronous in the sense that that something can be done while something else is also being done.
This applies to things like XHR requests as well, even though the XHR request are indeed dispatched asynchronously, the responses are all handled synchronously one at a time.
Your specific example is a bit odd in that it's not another javascript function that is blocking, it's a browser security feature that is making sure you want to let the previous javascript operation take you away from the current page. The concept is the same though.
Is there such a thing?
I know that I can hook my function on the click event of all links, but there are other situations where a page is changed, like refresh or when a different script changes the window.location
In the end, I did it by sending a string trough postMessage from the unload event, like this:
$(window).bind('unload', function(e){
window.parent.postMessage('unloading');
});
in the parent document:
$(window).bind('message', function(e){
if(e.originalEvent.data == 'unloading'){
// ajax stuff here
}
});
It appears to work.
I probably should have mentioned that there's a iframe involved :)
There's the beforeunload event, which is fired when the page is being torn down (either to follow a link, or if the window is being closed, or refresh, etc.). Example:
window.onbeforeunload = function(event) {
var s = "You have unsaved changes. Really leave?";
event = event || window.event;
if (event) {
// This is for IE
event.returnValue = s;
}
// This is for all other browsers
return s;
}
There are, for obvious reasons, very strict limits on what you can do in the handler of the beforeunload event, and as you can see above beforeunload handlers have a different signature than normal event handlers. Basically, your code can't do anything asynchronous, can't open new windows, and can't cancel the event. It can return a string, and if it does, the browser will pop up a window asking whether you really want to leave the page, and including your string in that pop-up.
From your comment on the question:
I need it before so I can fire a ajax request and update some things...
The way to do that here many years after the question was originally asked is with the beacon API. This lets you send a non-blocking asynchronous request to the server without slowing down the process of the browser tearing down your page and navigating to the next:
navigator.sendBeacon("/path/to/notify", optionalData);
It's a send-and-forget, but the browser doesn't cancel it when your page is torn down (like it does a standard asynchronous ajax request). Instead, it allows that request to complete even though your page has been removed.
Back in 2012 when this answer was originally written, you could usually get away with a synchronous ajax call (async: false) provided it didn't take too long. But you can't reliably do that now (and it was never a good idea, it holds up the UI).
jQuery has unload function:
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.
Note that this should be binded to window object instead of document:
$(window).unload(function() {
// do something
});
You can also bind handler to beforeunload event:
$(window).bind('beforeunload', function() {
// do something, preferably ajax request etc
return 'are you sure?';
});
When a page is reloaded, whatever was there before will be gone. Thus, it seems like what you're talking about is something you'd do at DOMReady or "load" in the new page, since you can't "push" code from the former page into the new context.
Consider the following code:
$(window).unload(function () {
console.log('foo');
});
If I trigger the unload event by navigating to a different URL, the event doesn't fire until the browser begins to get a response.
i.e. if the DNS lookup takes a long time, or the remote server takes time to respond (the loader animating anti-clockwise in Firefox, the event only fires once it starts rotating clockwise)
Is there another event I can listen to that happens as soon as navigation begins?
I realise I could attach to link clicks and intercept there, but that's just going to be hacky because there countless edge cases I'd have to manually capture here. OnUnload is the sensible place, but it doesn't behave as I want :(
thoughts?
There's window.onbeforeunload that might do what you're looking for.
I am developing a Firefox extension. My extension needs to get notified when a page completes loading. To implement this I am using DOMContentLoaded event. This works fine most of the times. But while visiting few sites (like nytimes.com), this event is not getting triggered at all. I am not sure whether these sites are using some special scripts.
Is there any workaround for this? Or is there a better way to implement what I am trying to do?
DOMContentLoaded may not be what you need...
According to MDN
Fired at the page's Document object when parsing of the document is
finished. By the time this event fires, the page's DOM is ready, but
the referenced stylesheets, images, and subframes may not be done
loading; use the "load" event to detect a fully-loaded page.
https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
So, it is possible that nytimes.com and others my be using frames or complex CSS and that is why you are not getting the correct trigger.
As mentioned above, the "fix" is to
use the "load" event to detect a fully-loaded page