What happens if multiple scripts set window.onload? - javascript

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.

Related

Run a function when another function is called

I'm wondering how to run a function when another function is called. addEventListener only runs events like "click", "mouseover", etc. However, I'd like to listen for a function call.
EXAMPLE:
Function 1 is called. Afterwards, Function 2 runs because it saw that Function 1 was called.
Is there an addEventListener alternative for simple functions and not events? I can't seem to find any.
My goal was to simply run a function everytime a user did something like call for when something was hidden in jQuery or by another JavaScript library or just simply another external JavaScript file with some code I added in.
Introducing a very hacky way
Since what you are trying to achieve is basically hacking some existing system (you shouldn't run into this problem if you have control over both sides and design your code properly).
It looks like your function is declared globally as well. In that case:
1. store the existing function in a variable
2. overwrite that function with your implementation
3. call the function variable at the start
function myFunction(){
//This is the main function
alert('Hello, this is part of the message!');
}
var tempfunc = myFunction;
window.myFunction = function() {
tempfunc();
// do what you need to do in the event listener here
alert('Hello, this is the other part of the message!');
}
EDIT:
The original question had the requirement that the original function cannot be modified, hence my solution. Since they it appears the question has changed.
You will have trigger an event inside myFunction and listen to that event.
function myFunction(){
//This is the main function
alert('Hello, this is part of the message!');
// trigger the event
var event = new CustomEvent("event", { "detail": "Example of an event" });
document.dispatchEvent(event);
}
// handle here;
document.addEventListener("event", function(){
//This is the secondary function
//or the function I need to run after the main function is called
alert('Hello, this is the other part of the message!');
});
// call main
myFunction();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Simple test!</p>
<p>Long story short, you get message 1, but message 2 never pops up!</p>
Is there an addEventListener alternative for simple functions and not
events? I can't seem to find any.
My goal was to simply run a function everytime a user did something
like call for when something was hidden in jQuery or by another
JavaScript library or just simply another external JavaScript file
with some code I added in.
You can use jQuery.Callbacks()
var callbacks = $.Callbacks();
function handleCallback1(message) {
console.log(message, this)
};
function handleCallback2(message) {
if (this.tagName === "DIV") {
this.style.color = "green";
} else {
this.nextElementSibling.style.color = "blue";
}
};
$("button, div").on("click", function() {
callbacks.fireWith(this, ["called from " + this.tagName])
});
callbacks.add(handleCallback1, handleCallback2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<button>click</button>
<div>click</div>

Run Two Functions (One In External File, One In Inline Javascript) On window.onload

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 */
};

How to fire an event immediately?

I'm binding an event like this, using prototype js:
$('country').observe('change',function(e) { ... });
How can I fire it once immediately?
in jQuery, I'd just tack on a .triggerHandler('change'). Is there something similar in prototype?
Use the load event. Something like this:
// calls addListeners when the document loads
Event.observe(window, 'load', addListeners, false);
function addListeners() {
// called onLoad
fireOnce();
// observer for the country dropdown
$('country').observe('change', function(event) {
fireOnChange();
});
}
function fireOnce() {
// do something
}
function fireOnChange() {
// do something
}
When the document loads, fireOnce() will execute. I use this technique all the time.
If using an extension is an option, I have had success in the past with event.simulate for this purpose.
It'll allow you to do something like:
$('country').simulate('change');
Try this:
var handler = function(e) {...};
$("country").observe("change",handler);
handler();
Alternatively (less readable, avoids temporary variable):
$("country").observe("change",(function(e) { ... return arguments.callee;})());
However, in both cases you will not be able to use this as you might expect. This solution is better suited to more general callbacks such as for setInterval
...if you know that it exists, and you know that you're not waiting for pageload or waiting for a script to load, why not just:
(function (el) {
if (!el) { return; }
doSomething(el);
}(document.getElementById("country")));

Adding multiple onload handlers

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!

Attach a body onload event with JS

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.

Categories