tags:

views:

15466

answers:

12

For all major browsers (except IE), the JavaScript onload event doesn't fire when the page loads as a result of a Back button operation - it only fires when the page is first loaded.

Can someone point me at some sample cross-browser code (Firefox, Opera, Safari, IE ...) that solves this problem? I'm familiar with Firefox's pageshow event but unfortunately neither Opera or Safari implement this.

Thanks!

+5  A: 

jQuery's ready event was created for just this sort of issue. You may want to dig into the implementation to see what is going on under the covers.

ckramer
This was (thankfully!) fixed in jQuery 1.4.
Nickolay
A long time later, `ready` does not seem to be triggered in Firefox, when using the Back button. See also [Nickolay's answer](http://stackoverflow.com/questions/158319/cross-browser-onload-event-and-the-back-button/2218733#2218733).
Arjan
nor using Chrome..
Sirber
A: 

Thanks! I'll take a look.

Bill
+1  A: 

Bill, I dare answer your question, however I am not 100% sure with my guesses. I think other then IE browsers when taking user to a page in history will not only load the page and its resources from cache but they will also restore the entire DOM (read session) state for it. IE doesn't do DOM restoration (or at lease did not do) and thus the onload event looks to be necessary for proper page re-initialization there.

Sergey Ilinsky
+1  A: 

I can confirm ckramer that jQuery's ready event works in IE and FireFox. Here's a sample

<html>
<head>
 <title>Test Page</title>
 <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
 <script type="text/javascript">
  $(document).ready( function(){
    var d = new Date();
    $('#test').html( "Hi at " + d.toString() );
   }
  );
 </script>
</head>
<body>
 <div id="test"></div>
 <div>
  <a href="http://www.google.com"&gt;Go!&lt;/a&gt;
 </div>
</body>
</html
palehorse
A: 

OK, I tried this and it works in Firefox 3, Safari 3.1.1, and IE7 but not in Opera 9.52.
If you use the example shown below (based on palehorse's example), you get an alert box pop-up when the page first loads. But if you then go to another URL, and then hit the Back button to go back to this page, you don't get an alert box pop-up in Opera (but you do in the other browsers).

Anyway, I think this is close enough for now. Thanks everyone!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>
Bill
+4  A: 

OK, here is a final solution based on ckramer's initial solution and palehorse's example that works in all of the browsers, including Opera. If you set history.navigationMode to 'compatible' then jQuery's ready function will fire on Back button operations in Opera as well as the other major browsers.

This page has more information.

Example:

history.navigationMode = 'compatible';
$(document).ready( function(){
                                alert('test');
                             }
                 );

I tested this in Opera 9.5, IE7, FF3 and Safari and it works in all of them.

Bill
+16  A: 

Guys, I found that JQuery has only one effect: the page is reloaded when the back button is pressed. This has nothing to do with "ready".

How does this work? Well, JQuery adds an onunload event listener.

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

By default, it does nothing. But somehow this seems to trigger a reload in Safari, Opera and Mozilla -- no matter what the event handler contains.

[edit(Nickolay): here's why it works that way: webkit.org, developer.mozilla.org. Please read those articles (or my summary in a separate answer below) and consider whether you really need to do this and make your page load slower for your users.]

Can't believe it? Try this:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com"&gt;click me, then press the back button</a>
</body>

You will see similar results when using JQuery.

You may want to compare to this one without onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com"&gt;click me, then press the back button</a>
</body>
Pumbaa80
@Pumbaa80, you're right -- I gave this a try in Firefox 3, and reproduced your results. Weird!
Jon Schneider
Very nice.. although this is an undocumented feature/bug though, and might simply stop working in future versions of the browser, but it's still interesting.
Wadih M.
This works as well (don't forget the onunload="" part, otherwise won't work on ff3):<body onload="alert('onload');" onunload="">
Wadih M.
This is because the browser assumes the page is uncacheable if it has a `onunload` handler (the page has already destroyed everything; why cache it?).
Casey Hope
+2  A: 

If I remember rightly, then adding an unload() event means that page cannot be cached (in forward/backward cache) - because it's state changes/may change when user navigates away. So - it is not safe to restore the last-second state of the page when returning to it by navigating through history object.

+7  A: 

The modern browsers (Firefox, Safari/Chrome, and Opera) all support the special "back/forward" cache (I'll call it bfcache, which is a term invented by Mozilla), involved when the user navigates Back. Unlike the regular (HTTP) cache, it captures the complete state of the page (including the state of JS, DOM). This allows it to re-load the page very quickly and exactly as the user left it, which is what the user wants.

The load event is not supposed to fire when the page is loaded from this bfcache. For example, if you created your UI in the "load" handler, and the "load" event was fired once on the initial load, and the second time when the page was re-loaded from the bfcache, the page would end up with duplicate UI elements.

This is also why adding the "unload" handler stops the page from being stored in the bfcache (thus making it slower to navigate back to) -- the unload handler could perform clean-up tasks, which could leave the page in unworkable state.

For pages that need to know when they're being navigated away/back to, Firefox 1.5+ and some next version of Safari (which contains the fix for bug 28758) supports special events called "pageshow" and "pagehide".

References: http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ and https://developer.mozilla.org/En/Using_Firefox_1.5_caching.

Nickolay
That's very cool. I'm in a situation currently where my dom manipulations don't appear to be saved in the bfcache. Are there any situations where you might expect that?
Benson
@Benson: the possible reasons when Firefox will not save your page in bfcache are listed on the dev.m.o page I linked to. I don't think it's possible to have the page saved to bfcache, but certain DOM state not be saved.
Nickolay
Awesome, thank you!
Benson
Nickolay, I get your reluctance to force a reload and undo the good work done by the bfcache, but is there another way update the dom of the page in the bfcache? For example, consider the situation where I go from a page that has a list of messages to one of them, and when I go "back" I want the read/unread indicator to change. How can this be done without reloading the page?
Greg
@Greg: you mean as a developer controlling the page? Fire off an ajax request from a 'pageshow' listener.
Nickolay
+1  A: 

I ran into a problem that my js was not executing when the user had clicked back or forward. I first set out to stop the browser from caching but this didn't seem te be the problem. My javascript was set to execute after all of the libraries etc. where loaded. I check these with the readyStateChange event.

After some testing i found out that the readyState of an element in a page where back has been clicked is not 'loaded' but 'complete'. Adding || element.readyState == 'complete' to my conditional statement solved my problems.

Just thought i'd share my findings, hopefully they will help someone else.

Brian Heese
A: 

I tried the solution from Bill using $(document).ready... but at first it did not work. I discovered that if the script is placed after the html section, it will not work. If it is the head section it will work but only in IE. The script does not work in Firefox.

Johann
A: 

for the people who don't want to use the whole jquery library i extracted the implementation in separate code. It's only 0,4 KB big.

You can find the code, together with a german tutorial in this wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

d0nut
Link shows empty page
Marco Demajo