I have some web pages which rely on body.onload (or, equivalently, window.onload) to set them up properly. Sometimes onload is not being called.
Is there a trick with some web browser (ideally Chrome, where this apparently happens most often) which will tell me what exactly is preventing the page from loading successfully?
Clue: this rarely (maybe even never) happens when I hit F5 to reload the whole page, but more generally it happens if a page has been arrived-at by clicking a link or pasting the url into the address bar. Is there a quirk of onload semantics that might be tripping me up?
N.B. The scripts themselves are not producing any errors in the console.
I think you want window.onload
I have tested such cases, and none of the following will work:
var callback = function() { alert("Body loaded"); };
$("body").load(callback);
document.body.addEventListener("load",callback,false);
However, document.body.onload seems to work fine. Make sure that body is correctly namespaced:
document.body //<body>
body //Reference error
If you're talking about:
<body onload="callback();"></body>
Then go back and review your code, because it should work.
Personally, I suggest using the load event of the window object or a framework's ready event.
//Execute when the window is loaded
var callback = function() {
//Your code goes here...
};
if (window.addEventListener) window.addEventListener("load",callback,false);
else window.attachEvent("load",callback);
With jQuery, you only need the following:
$(window).load(callback);
jQuery's ready event is as follows:
$(document).ready(callback);
//Or just:
$(callback);
MooTools use this:
window.addEvent("domready",callback);
And different libraries all have their own way.
Related
I just discovered that the source of my issues is that the parent HTML makes calls to controls in a child IFRAME but is too quick about that and, sometimes, the super onLoad attempts to do so before the sub onLoad had a chance to add stuff to the DOM.
What can I do about it?
I've tried to set up some kind of feed-back from onLoad in the child. Failed miserably with so many strange errors that they can be summarized by dude, just please don't.
I've tried to set up a delayer, which is ugly of epic proportions and not 100% reliable.
EDIT:
In onload I do this:
var stuff = getReferenceToStuff();
var someDiv = stuff.contentWindow.document.getElementById("someDiv");
someDiv.className = "classy";
The problem is that sometimes the reference someDiv is null and sometimes (often when I reload the page by F5), it points to the correct element. I know it's because the contents of the IFRAME are a bit slower.
So my questions is this. How can I ensure that onload is postponed until the embedded IFRAME component's onload ensures that it's been loaded and all the components are there?
The onLoad event isn't always working correctly on document. It works correctly on each element though.
var iframes = document.getElementsByTagName('iframe'),
counter = 0,
max = iframes.length;
[].forEach.call(iframes, iLoaded);
function iLoaded() {
if (++counter === max) {
callback();
}
}
function callback() {
// All the iframes are loaded
}
When using window.onload all content of the body, including content of the iframes and all other resources like images, should be loaded before the onload is fired. However, some browsers have had problems with timing on firing onload, i.e. different browsers trigger the event in different stage of page parsing.
If you're using DOMContentLoaded or jQuery's $(document).ready(), only the HTML of the main page is loaded, but some resources are still under work (including iframe's content loading). I'm not aware what happens if you attach an inline listener for the iframe element itself.
If there's timing problems, maybe not trigger the function needing iframe reference in main window at all. Instead invoke that function in main window in irame's window.onload. But even this won't tackle the problem, if you're using some asynchronous technique to populate the iframe. In this case you need to invoke the function in main window after all requests have been completed.
(Now you maybe also know, what are the codesnippets I'd like to see in your post : ) ).
I have 2 solutions to your problem:
If you are on HTML5, use window.postMessage. Just message from iFrame to the parent in the onload of iFrame. Parent should register handler in <script> tag, that appears before iFrame.
Add a callback function to window in the '' tag before iFrame. This function is called by iFrame when it's load is complete. Here is the basic template.
Here is the sample template:
<script>
window.iframeCallback = function(message) {
// first clear the temp function we added to the window
// It is a bad practice to corrupt the global namespace
delete window.iframeCallback;
// you do your work here
};
</script>
..
..
<!-- iFrame should appear after the above script-->
<iframe/>
I'm using this technique to detect when the current tab gains focus and this one to set focus on the <applet>, however I get a couple of errors since the applet isn't ready when the first onFocus occurs during page-load. It doesn't appear to stop anything working but errors are not ideal!
In a perfect world I'd only set the focus handlers once the applet is ready. Alternatively the focus handler would check the applet is valid before 'touching' it... either is fine depending on which is simpler. Non-jQuery answers preferred please!
My HTML looks like:
<head>
<script language="javascript">
function focusIn()
{
document.myApplet.requestFocus();
}
if ("onfocusin" in document)
document.onfocusin = focusIn;
else
window.onfocus= focusIn;
</script>
</head>
At the end of the Applet.start() method, call a JS function to indicate 'applet is ready'. The applet might even be able to detect a tab change to the applet page or the browser being restored from minimized.
window.popup = window.open($(this).attr('href'), 'Ad', 'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');
$(window.popup).onload = function()
{
alert("Popup has loaded a page");
};
This doesn't work in any browser I've tried it with (IE, Firefox, Chrome). How can I detect when a page is loaded in the window (like an iframe onload)?
var myPopup = window.open(...);
myPopup.addEventListener('load', myFunction, false);
If you care about IE, use the following as the second line instead:
myPopup[myPopup.addEventListener ? 'addEventListener' : 'attachEvent'](
(myPopup.attachEvent ? 'on' : '') + 'load', myFunction, false
);
As you can see, supporting IE is quite cumbersome and should be avoided if possible. I mean, if you need to support IE because of your audience, by all means, do so.
If the pop-up's document is from a different domain, this is simply not possible.
Update April 2015: I was wrong about this: if you own both domains, you can use window.postMessage and the message event in pretty much all browsers that are relevant today.
If not, there's still no way you'll be able to make this work cross-browser without some help from the document being loaded into the pop-up. You need to be able to detect a change in the pop-up that occurs once it has loaded, which could be a variable that JavaScript in the pop-up page sets when it handles its own load event, or if you have some control of it you could add a call to a function in the opener.
As noted at Detecting the onload event of a window opened with window.open, the following solution is ideal:
/* Internet Explorer will throw an error on one of the two statements, Firefox on the other one of the two. */
(function(ow) {
ow.addEventListener("load", function() { alert("loaded"); }, false);
ow.attachEvent("onload", function() { alert("loaded"); }, false);
})(window.open(prompt("Where are you going today?", location.href), "snapDown"));
Other comments and answers perpetrate several erroneous misconceptions as explained below.
The following script demonstrates the fickleness of defining onload. Apply the script to a "fast loading" location for the window being opened, such as one with the file: scheme and compare this to a "slow" location to see the problem: it is possible to see either onload message or none at all (by reloading a loaded page all 3 variations can be seen). It is also assumed that the page being loaded itself does not define an onload event which would compound the problem.
The onload definitions are evidently not "inside pop-up document markup":
var popup = window.open(location.href, "snapDown");
popup.onload = function() { alert("message one"); };
alert("message 1 maybe too soon\n" + popup.onload);
popup.onload = function() { alert("message two"); };
alert("message 2 maybe too late\n" + popup.onload);
What you can do:
open a window with a "foreign" URL
on that window's address bar enter a javascript: URI -- the code will run with the same privileges as the domain of the "foreign" URL
The javascript: URI may need to be bookmarked if typing it in the address bar has no effect (may be the case with some browsers released around 2012)
Thus any page, well almost, irregardless of origin, can be modified like:
if(confirm("wipe out links & anchors?\n" + document.body.innerHTML))
void(document.body.innerHTML=document.body.innerHTML.replace(/<a /g,"< a "))
Well, almost:
jar:file:///usr/lib/firefox/omni.ja!/chrome/toolkit/content/global/aboutSupport.xhtml, Mozilla Firefox's troubleshooting page and other Jar archives are exceptions.
As another example, to routinely disable Google's usurping of target hits, change its rwt function with the following URI:
javascript: void(rwt = function(unusurpURL) { return unusurpURL; })
(Optionally Bookmark the above as e.g. "Spay Google" ("neutralize Google"?)
This bookmark is then clicked before any Google hits are clicked, so bookmarks of any of those hits are clean and not the mongrelized perverted aberrations that Google made of them.
Tests done with Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 UA string.
It should be noted that addEventListener in Firefox only has a non-standard fourth, boolean parameter, which if true allows untrusted content triggers to be instantiated for foreign pages.
Reference:
element.addEventListener | Document Object Model (DOM) | MDN:
Interaction between privileged and non-privileged pages | Code snippets | MDN:
This did the trick for me; full example:
HTML:
Click for my popup on same domain
Javascript:
(function(){
var doc = document;
jQuery('.import').click(function(e){
e.preventDefault();
window.popup = window.open(jQuery(this).attr('href'), 'importwindow', 'width=500, height=200, top=100, left=200, toolbar=1');
window.popup.onload = function() {
window.popup.onbeforeunload = function(){
doc.location.reload(true); //will refresh page after popup close
}
}
});
})();
onload event handler must be inside popup's HTML <body> markup.
First of all, when your first initial window is loaded, it is cached. Therefore, when creating a new window from the first window, the contents of the new window are not loaded from the server, but are loaded from the cache. Consequently, no onload event occurs when you create the new window.
However, in this case, an onpageshow event occurs. It always occurs after the onload event and even when the page is loaded from cache. Plus, it now supported by all major browsers.
window.popup = window.open($(this).attr('href'), 'Ad', 'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');
$(window.popup).onpageshow = function() {
alert("Popup has loaded a page");
};
The w3school website elaborates more on this:
The onpageshow event is similar to the onload event, except that it occurs after the onload event when the page first loads. Also, the onpageshow event occurs every time the page is loaded, whereas the onload event does not occur when the page is loaded from the cache.
The core problem seems to be you are opening a window to show a page whose content is already cached in the browser. Therefore no loading happens and therefore no load-event happens.
One possibility could be to use the 'pageshow' -event instead, as described in:
https://support.microsoft.com/en-us/help/3011939/onload-event-does-not-occur-when-clicking-the-back-button-to-a-previou
Simple solution:
new_window = window.open(...);
new_window.document.write('<body onload="console.log(1);console.log(2);></body>');
When I use the back button on Firefox to reach a previously visited page, scripts on that page won't run again.
Is there any fix/workaround to have the scripts execute again when viewing the page the second time?
Please note that I have tested the same pages on Google Chrome and Internet Explorer and they work as intended.
Here are the files and the steps I used to test the problem:
(navigate to 0.html, click to get to 1.html, back button)
0.html
<html><body>
<script>
window.onload = function() { alert('window.onload alert'); };
alert('inline alert');
</script>
Click Me!
</body></html>
1.html
<html><body>
<p>Go BACK!</p>
</body></html>
Set an empty function to be called on window.onunload:
window.onunload = function(){};
e.g.
<html><body>
<script type="text/javascript">
window.onload = function() { alert('window.onload alert'); };
window.onunload = function(){};
alert('inline alert');
</script>
Click Me!
</body></html>
Source:
http://www.firefoxanswer.com/firefox/672-firefoxanswer.html (Archived Version)
When I use the back button on Firefox to reach a previously visited page, scripts on that page won't run again.
That's correct and that's a good thing.
When you hit a link in Firefox (and Safari, and Opera), it does not immediately destroy your page to go onto the next one. It keeps the page intact, merely hiding it from view. Should you hit the back button, it will then bring the old page back into view, without having to load the document again; this is much faster, resulting in smoother back/forward page transitions for the user.
This feature is called the bfcache.
Any content you added to the page during the user's previous load and use of it will still be there. Any event handlers you attached to page elements will still be attached. Any timeouts/intervals you set will still be active. So there's rarely any reason you need to know that you have been hidden and re-shown. It would be wrong to call onload or inline script code again, because any binding and content generation you did in that function would be executing a second time over the same content, with potentially disastrous results. (eg. document.write in inline script would totally destroy the page.)
The reason writing to window.onunload has an effect is that the browsers that implement bfcache have decided that — for compatibility with pages that really do need to know when they're being discarded — any page that declares an interest in knowing when onunload occurs will cause the bfcache to be disabled. That page will be loaded fresh when you go back to it, instead of fetched from the bfcache.
So if you set window.onunload= function() {};, what you're actually doing is deliberately breaking the bfcache. This will result in your pages being slow to navigate, and should not be used except as a last resort.
If you do need to know when the user leaves or comes back to your page, without messing up the bfcache, you can trap the onpageshow and onpagehide events instead:
window.onload=window.onpageshow= function() {
alert('Hello!');
};
You can check the persisted property of the pageshow event. It is set to false on initial page load. When page is loaded from cache it is set to true.
window.onpageshow = function(event) {
if (event.persisted) {
alert("From bfcache");
}
};
For some reason jQuery does not have this property in the event. You can find it from original event though.
$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
alert("From bfcache");
}
});
In my case window.onunload with an empty function didn't help (I tried to set a value for dropdown when user uses backwards button). And window.onload didn't work for other reason - it was overridden by <body onload="...">.
So I tried this using jQuery and it worked like a charm:
$(window).on('pageshow', function() { alert("I'm happy"); });
Wire in an "onunload" event that does nothing:
<html><body>
<script type="text/javascript">
window.onload = function() { alert('window.onload alert'); };
window.onunload = function(){};
alert('inline alert');
</script>
Click Me!
</body></html>
As far as i know Firefox does not fire onLoad event on back.
It should trigger onFocus instead based from this link here.
A simple way to cause a page to execute JavaScript when the user navigates back to it using browser history is the OnPopState event. We use this to pause and replay the video on our home page (https://fynydd.com).
window.onpopstate = function() {
// Do stuff here...
};
for some cases like ajax operations url change listener can be used
$(window).on('hashchange', function() {
....
});
I'm having some issues with a jQuery AJAX call. My code works fine when I request a page with no javascript in it, but when I have script tags in my code, things start to get weird.
It seems that any script tags referencing external URLs cause the browser to redirect. In firefox, the page goes blank. In safari, the page clears and loads with the content of the AJAX response. In both browsers, the URL doesn't change.
To be specific about my problem; I have a tab control in which I'm trying to embed the walkscore widget. Since it's pretty heavy on the client side, I only want to actually load it once the user clicks the tab it's in. The walkscore AJAX page looks like this:
<script type="text/javascript">
var ws_address = "1 Market St, San Francisco";
var ws_width = "500";
</script>
<script type="text/javascript" src="http://www.walkscore.com/tile/show-tile.php?wsid=MY_WSID">
</script>
Is there some restriction on script tags referencing external sites on AJAX calls? Is there any nice way around this?
-- Edit --
OK I've been playing with it for a bit and have narrowed down the problem a little. Let me try give a better explanation at the same time:
I have two files, index.html and walkscore.html
index.html
function widget() {
var widget = $('#walkscore');
$.get('/walkscore.html', function(data) {
$('#loading').slideUp(function() {
widget.html(data);
loaded[name] = true;
widget.slideDown();
});
});
}
walkscore.html - as shown in the top code block
In index.html, I have a link that calls the widget function. Whenever I click this link, the whole page is replaced by the output of the js file. It happens regardless of the domain the js file is from. It only seems to happen with js files that have document.write in them. It behaves in exactly the same way when I use the $.getScript function, even when it's in index.html
-- Edit --
It seems it has everything to do with the document.write. I made a copy of the walkscore javascript and replaced all occurrences of document.write with jquery.html, and it seems to work properly. I'm (obviously) a js noob. Is this the expected behavior of document.write? How come it doesn't do it when I include the script on a page load?
Load script separately from html content, you can use $.getScript( ).
It has to do with the document.write in the response.. I was able to fix this in Firefox by doing this:
<script type="text/javascript">
// save default document.write function so we can set it back
var write_func_holder = document.write;
// redefine document.write to output text target div
document.write = function(text) {
$('#ad_container').html($('#ad_container').html() + text);
}
</script>
<script language="JavaScript" type="text/javascript" src="javascriptfile">
</script>
<script type="text/javascript">
// reset document.write function
document.write = write_func_holder;
</script>
I'm still getting an issue in Safari where the browser refreshes to a blank page with just the content of the document.write and IE6, IE7 doesn't do anything at all. Firefox works though.
I hope this helps someone figure out what wrong and they in turn can fix the IE6/7 and Safari issues
It happens because of the document.write call. Here's some info on what's going on:
Writing After A Page Has Been Loaded
If document.write() is invoked after a page has finished loading, the entire static (non-script generated) content of a page will be replaced with the write method's parameter. This scenario is most often played out when the write method is invoked from an event handler - whether the method is in a function called by the event handler or alone inside the handler - because event handlers are triggered after a page has finished loading. This is important to know because static content replacement is not always the desired result. Another common scenario for content overwite has to do with writing content to a new window. In this case, the overwrite of blank page is the goal.
(source)
The solution I went with was to eliminate the document.write commands, and replace the content of a div instead. If you're loading an external script, and have no control over it, you can replace the document.write function with your own. It's discussed here:
http://www.webxpertz.net/forums/showthread.php?threadid=11658
Hope that helps someone out there!
Replacing document.write is the way to go. This is shameless self promotion, but if you have a non-trivial case, writeCapture.js handles all the edge cases.
I would first check the response of that script source, maybe something in that causes the unwanted behavior.
I am experiencing the EXACT same behaviour and spent some frustrating hours last night trying to figure out what the problem was and searching for answers to no avail. I'm surprised this is mentioned anywhere in the jquery docs as it seems like a plausible problem not some crazy never-to-be-encountered bug.
Anyway, here's my story in case anyone searches for something related.
I have a jquery enabled page that loads some content into a div using $.ajax(), it all works perfectly. What I needed to do was include one of those twitter retweet buttons that shows a count and enables you to tweet about the content on the page. To do this a simple piece of javascript from them should be included on the page.
<script type="text/javascript" src="http://www.retweet.com/static/retweets.js"></script>
So in theory, that script tag should be returned in the ajax call and jquery should execute it and include the result of it, as I specified the data type as html in the $.ajax() call.
The external script on closer inspection does:
if(!url)
{
var url=window.location.href;
}
if(!size)
var size="big";
var height="75";
var width="54"
if(size=="small")
{
height="22";
width="120";
}
if(!username)
var username="none";
url=url.replace("?", "*");
var src="http://www.retweet.com/widget/button/"+size+"/"+username+"/"+url;
document.write('<iframe src="'+src+'" height="'+height+'" width="'+width+'" frameborder="0" scrolling="no"></iframe>');
Which obviously bombs out on the document.write.
Tonight i'll try the methods in this post and see if they work, thanks for the info.