Adding multiple onload handlers

11,435

Solution 1

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.

Solution 2

You need to look at addEventListener and attachEvent, which are native implementations of your addOnloadHandler.

Solution 3

PPK's reference on addEventListener explains how do this pretty well:

http://www.quirksmode.org/js/events_advanced.html

Solution 4

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!

Share:
11,435
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    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"> 
      <a href="http://www.whatever.com" id="redirect"> Wellcome to our site... c'mon in! </a> 
     </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!