How do I attach a body onload event with JS in a cross browser way? As simple as this?
document.body.onload = function(){
alert("LOADED!");
}
This takes advantage of DOMContentLoaded - which fires before onload - but allows you to stick in all your unobtrusiveness...
window.onload - Dean Edwards - The blog post talks more about it - and here is the complete code copied from the comments of that same blog.
// Dean Edwards/Matthias Miller/John Resig
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
// do stuff
};
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
/* for Internet Explorer */
/*#cc_on #*/
/*#if (#_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*#end #*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = init;
Why not use window's own onload event ?
window.onload = function () {
alert("LOADED!");
}
If I'm not mistaken, that is compatible across all browsers.
Cross browser window.load event
function load(){}
window[ addEventListener ? 'addEventListener' : 'attachEvent' ]( addEventListener ? 'load' : 'onload', load )
document.body.onload is a cross-browser, but a legacy mechanism that only allows a single callback (you cannot assign multiple functions to it).
The closest "standard" alternative, addEventListener is not supported by Internet Explorer (it uses attachEvent), so you will likely want to use a library (jQuery, MooTools, prototype.js, etc.) to abstract the cross-browser ugliness for you.
jcalfee314's idea worked for me - I had a window.onload = onLoad which meant that the functions in <body onload="..."> were not being called (which I don't have control over).
This fixed it:
oldOnLoad = window.onload
window.onload = onLoad;
function onLoad()
{
oldOnLoad();
...
}
Edit: Firefox didn't like oldOnLoad = document.body.onload;, so replaced with oldOnLoad = window.onload.
There are several different methods you have to use for different browsers. Libraries like jQuery give you a cross-browser interface that handles it all for you, though.
Why not using jQuery?
$(document).ready(function(){}))
As far as I know, this is the perfect solution.
Related
There are a number of posts on StackOverflow and other websites regarding the problem of avoiding namespace collisions. In my scenario, I just want a method in my JavaScript to be executed after the DOM is accessible.
If I do the following will it avoid namespace collisions?
<script type="text/javascript">window.onload = function() { //Define my namespace var here, and execute all my code }</script>
What if a script that is injected later also sets an onload function ? Will mine get overwritten? I'm fully aware that I can test this out, but I would also like some feedback as I am new to JavaScript and there could be a number of other scenarios which will do the something that I am not aware of.
EDIT: I need to support only Safari 5.0+
Yes, the last one will overwrite the previous ones.
The solution: use the new event API: addEventListener.
This is a fine Javascript way to do it right
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(nameOfSomeFunctionToRunOnPageLoad);
addLoadEvent(function() {
/* more code to run on page load */
});
Explained Source
There's lots of information on this, but here's the short version:
if you want to play nicely with onload, you can do
var prev_onLoad = window.onload;
window.onload = function() {
if (typeof(prev_onLoad)=='function')
prev_onLoad();
// rest of your onLoad handler goes here
}
and hope that other's play nicely or make sure that's the last setting of onload in the code.
However, more modern browsers have event registration functions (addEventListener and attachEvent on IE) which take care of this chaining among other things. Quite a few cross-browser onload event functions have been written which take care of this logic for you.
It'll be overriden .
In Javascript, when you define handle event like
window.onload = function(){
console.log("in Load function 1");
};
window.onload = function(){
console.log(" In load function 2");
};
That will make an " assign " window.onload => function() . And window.onload will be assign to last function .
But in jQuery,
You can handle event in many times and the browser will make all
$("body").on("click",function(){
console.log("make a callback function 1");
});
$("body").on("click",function(){
console.log("make a callback function 2");
});
Because jQuery make a callback not "assign".
Hope it helps you.
I'm developing a website and I have an external JavaScript file that is linked to every page of the site which executes when the window.onload event is fired. The JavaScript executes fine on all pages which do not contain any inline JavaScript.
Any page that contains inline JavaScript also contains a JavaScript function which executes when the window.onload event is fired.
The problem I'm having is that the external JavaScript does not execute when window.onload is fired, only the internal JavaScript does. It appears as if the inline JavaScript function overwrites the function from the external JavaScript file.
I know that my external JavaScript file is first executed and then the inline JavaScript is executed. Is there anyway that I can execute both functions on window.onload?
How about changing the script that executes second to something like this:
var onload = function () {
// Do something
alert('Hello');
};
if(window.onload) {
// If a function is already bound to the onload event, execute that too.
var fn = window.onload;
window.onload = function () {
fn();
onload();
};
} else {
window.onload = onload;
}
Or use a library like jQuery which lets you do:
$(document).ready(function() {
alert('Hello');
}
This might be more of a work around than a proper fix but could you put your inline JS at the bottom of the html page so it is automatically called after the page is loaded. That will mean you don't have to actually use window.onload()
Two ways :
1 - Use addEventListener.
window.addEventListener("load", function(){ /*code*/ }, false);
2 - Use a hack like this:
var func = window.onload;
window.onload = function() {
if ( func ) func();
/* code */
};
For reasons that are beyond my control I have to load jQuery via a dynamically appended <script> tag, and only do this upon some arbitrary event, not at page load.
My problem is in detecting the moment when jquery is ready, for the code below doesn't work:
(function(){
var s=document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src','http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js');
document.getElementsByTagName('head')[0].appendChild(s);
})()
$(document).ready(function() {
// something that uses jquery and currently doesn't work
});
How do I detect the moment when jquery is ready to be used in this particular configuration?
Thanks in advance
Use the onload and onreadystatechange event handlers:
var scr = document.createElement('script'),
head = document.getElementsByTagName('head')[0];
scr.onload = scr.onreadystatechange = function(){
if( scr.readyState ){
if(scr.readyState === 'complete' || scr.readyState === 'loaded'){
scr.onreadystatechange = null;
myReadyFunc();
}
}
else{
myReadyFunc();
}
};
head.insertBefore(scr, head.firstChild);
function myReadyFunc() {
$(document).ready(function() {
// something that uses jquery and currently doesn't work
});
}
An old-school answer :)
You can create a recursive polling function that check to see if the $ object exists eg:
function poller(){
if($.length != 0){
//do what you want
}else{
setTimeout(poller, 100);
}
}
And right after you load the jQuery script run the poller function.
You can handle the <script> element's onreadystatechange event, and, if this.readyState is complete or loaded, run your function.
For Firefox, handle the onload event.
You can expose this in a wrapper function which takes a function as a parameter, and calls it if jQuery has been loaded, or puts it in an array (to call in the load handler) if it's not loaded.
I have two js files, each one with its own window.onload handler. Depending on how I attach the two onload handlers to the window object I get a different behaviour on the second handler.
More specifically, here is my html file:
<html>
<head>
<title>Welcome to our site</title>
<script type="text/javascript" src="script1.js"> </script>
<script type="text/javascript" src="script2.js"> </script>
</head>
<body id="pageBody">
<h2 align="center">
Wellcome to our site... c'mon in!
</h2>
</body>
</html>
It loads two js files, script1.js and script2.js.
Here is the version of these two scripts that leads to the (at least by me) unexpected behaviour.
Script1.js:
window.onload = initAll1(); // attach first onload handler
function initAll1() {
alert("initAll1");
document.getElementById("redirect").onclick = foo; // attach an onclick handler
}
function foo() {
alert("we are in foo");
return false;
}
Script2.js:
addOnloadHandler(initAll2); // with this we should attach a second onload handler
function initAll2() {
alert("initAll2");
if (linkHasOnclickHandler(document.getElementById("redirect"))) {
alert("correct!");
}
else {
alert("wrong!");
}
}
function addOnloadHandler (newFunction) {
var oldevent = window.onload;
if (typeof oldevent == "function") {
window.onload = function() {
if (oldevent) {
oldevent();
}
newFunction();
};
}
else {
window.onload = newFunction;
}
}
function linkHasOnclickHandler() {
var oldevent = document.getElementById("redirect").onclick;
if (typeof oldevent == "function") {
return true;
}
else {
return false;
}
}
In Script2.js I tried to add the second onload handler in a nice noninvasive way using function addOnloadHandler(). This function does not make any assumption on whether there is already any onload handler attached to the window object. It is noninvasive because it should add the new handler without deleting previous ones.
The thing is that when loaded with addOnloadHandler(), initAll2() is not capable of detecting the fact that document.getElementById("redirect") already has foo() attached as an onclick event handler (see initAll1()). The alert message "wrong!" is triggered, which to me seems to be the wrong behaviour.
When I forget about addOnloadHandler() and attach both onload handlers in Script1.js using:
window.onload = function () {initAll1(); initAll2();};
then everything works as expected, and initAll2() launches the "correct!" alert message.
Is there something wrong about addOnloadHandler()? Could anybody make it work? I would really like to use it instead of the second method.
Thanks!
Just in case future people find this, and are looking for a way to use multiple event handlers when the object itself doesn't support addEventListener, attachEvent or some other form of listener stacking - i.e. it is a bespoke object, badly implemented. Then you can do the following:
object.onload = (function(pre){
return function(){
pre && pre.apply(this,arguments);
/// do what you need for your listener here
}
})(object.onload);
Each time you use the above code the previous onload listener is passed in as an argument, and when your new listener is triggered it runs the old listener first - meaning you can stack many listeners like this, if you so wish. However, this will only work for as long as the above code is always used to add listeners to your object. All your hard work will be undone if somewhere else it is overridden with a simple:
object.onload = function(){}
As a note to coders, if you are to implement a library, plugin or constructor, and it is possible other coders will take over your work. Please, please code the ability for multiple event listeners. It's really not that difficult.
You need to look at addEventListener and attachEvent, which are native implementations of your addOnloadHandler.
PPK's reference on addEventListener explains how do this pretty well:
http://www.quirksmode.org/js/events_advanced.html
Thanks for the answers!
I rewrote my script2.js using addEventListener and attachEvent like this:
//addOnloadHandler(initAll1); // it works only when uncommenting this
addOnloadHandler(initAll2);
function initAll2() {
alert("initAll2");
if (linkHasOnclickHandler(document.getElementById("redirect"))) {
alert("correct!");
}
else {
alert("wrong!");
}
}
function addOnloadHandler(newFunction) {
if (window.addEventListener) { // W3C standard
window.addEventListener('load', newFunction, false); // NB **not** 'onload'
}
else if (window.attachEvent) { // Microsoft
window.attachEvent('onload', newFunction);
}
}
function linkHasOnclickHandler(element) {
var oldevent = document.getElementById("redirect").onclick;
if (typeof oldevent == "function") {
return true;
}
else {
return false;
}
}
As you can see, addOnloadHandler() has been rewritten using the native implementations you guys mentioned. I left script1.js untouched.
The resulting code still does not work (i.e., the "wrong!" alert message is shown). It only works when I register the onload initAll1() handler twice by uncommenting the first line of code in script2.js.
Apparently, mixing
window.onload = handler1;
and
window.addEventListener('load', handler2, false);
or
window.attachEvent('onload', handler2);
does not work fine.
Is there any way to work around this problem that does not imply touching script1.js?
Just in case you wonder why I don't want to touch script1.js, the reason is that I want my code (script2.js) to be reusable in other projects as well, no matter which other js files each project uses. So, it should work with every possible event-handling registration method used in script1.js.
thanks once more for your help!
jQuery of course requires everything to be inside
$(document).ready = function() {};
similarly, svg-web requires:
window.onsvgload = function() {};
Is there a correct, elegant way to combine these that doesn't introduce any problems?
You can just bind the functions to run on the appropriate event, like this:
$(function() { //shortcut for $(document).ready(function() {
//stuff that needs the DOM to be ready
});
$(window).bind('svgload', function() {
//SVG stuff
});
There's no harm is using both, in fact that's the appropriate usage, always use the event you need, this is no different from document.ready vs window.load when you need images ready, not just the DOM.
If it matters, svgload happens after onload in the browsers that support it as of the time of this answer, not sure if that'll be consistent when other browsers support it though.
Finally found this in the 'user manual':
$(document).ready(function() {
window.addEventListener('SVGLoad', function() {
// ready to work with SVG now
}, false);
});