<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: addloadevent</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/addloadevent.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2004-05-26T06:30:37+00:00</updated><author><name>Simon Willison</name></author><entry><title>Executing JavaScript on page load</title><link href="https://simonwillison.net/2004/May/26/addLoadEvent/#atom-tag" rel="alternate"/><published>2004-05-26T06:30:37+00:00</published><updated>2004-05-26T06:30:37+00:00</updated><id>https://simonwillison.net/2004/May/26/addLoadEvent/#atom-tag</id><summary type="html">
    &lt;p id="p-0"&gt;Peter-Paul Koch &lt;a href="http://www.digital-web.com/articles/separating_behavior_and_structure_2/" title="Separating behavior and structure"&gt;recently wrote&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote cite="http://www.digital-web.com/articles/separating_behavior_and_structure_2/"&gt;&lt;p id="p-1"&gt;In my opinion, recent advances in JavaScript theory call for the removal of the event handlers that some Web developers-and all WYSIWYG editors-deploy in large masses in their XHTML files, where they don’t belong.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p id="p-2"&gt;&lt;acronym title="Peter-Paul Koch"&gt;PPK&lt;/acronym&gt; is talking about inline event attributes such as the infamous &lt;code class="html"&gt;onclick=""&lt;/code&gt; and &lt;code class="html"&gt;onmouseover=""&lt;/code&gt; which have infested our &lt;acronym title="HyperText Markup Language"&gt;HTML&lt;/acronym&gt; ever since Netscape introduced JavaScript back in version 2.0 of their browser. The alternative to these handlers is to add event handlers to elements after the document has loaded. &lt;acronym title="Peter-Paul Koch"&gt;PPK&lt;/acronym&gt; has detailed coverage of the various ways of doing this &lt;a href="http://www.quirksmode.org/js/introevents.html" title="Introduction to Events"&gt;on his QuirksMode site&lt;/a&gt;.&lt;/p&gt;

&lt;p id="p-3"&gt;In my work with unobtrusive JavaScript, I've found that by far the most common action I take is "registering" a script to be executed once the page has finished loading. There are a number of ways of doing this, which I described in my article &lt;a href="http://www.sitepoint.com/article/structural-markup-javascript"&gt;Enhancing Structural Markup with JavaScript&lt;/a&gt;. Unfortunately, none of them are perfect if you wish to write truly reusable scripts.&lt;/p&gt;

&lt;p id="p-4"&gt;For a script (such as my blockquote citations script discussed in the article) to be properly reusable, it needs to behave nicely in the presence of other scripts. This means that assigning a callback function directly to the &lt;code class="javascript"&gt;window.onload&lt;/code&gt; handler is out of the question as doing so will over-ride previously assigned callbacks from other scripts. The correct way of adding a handler to an event without over-riding other handlers is to use modern event attachment method, which sadly differ between &lt;acronym title="Internet Explorer"&gt;IE&lt;/acronym&gt;/Windows and other browsers. Scott Andrew's &lt;a href="http://www.scottandrew.com/weblog/jsjunk#events" title="addEvent / removeEvent"&gt;addEvent function&lt;/a&gt; handles the differences for you but comes with one major and rarely discussed drawback: it fails silently in &lt;acronym title="Internet Explorer"&gt;IE&lt;/acronym&gt;5/Mac. If you care about the many Mac users still on OS9, you need to support that browser.&lt;/p&gt;

&lt;p id="p-5"&gt;Anyway, I believe I've found a solution. Check this out:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;
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 */ 
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p id="p-6"&gt;The &lt;code class="javascript"&gt;addLoadEvent&lt;/code&gt; function takes as an argument another function which should be executed once the page has loaded. Unlike assigning directly to &lt;code class="javascript"&gt;window.onload&lt;/code&gt;, the function adds the event in such a way that any previously added onload functions will be executed first.&lt;/p&gt;

&lt;p id="p-7"&gt;The way this works is relatively simple: if &lt;code class="javascript"&gt;window.onload&lt;/code&gt; has not already been assigned a function, the function passed to &lt;code class="javascript"&gt;addLoadEvent&lt;/code&gt; is simply assigned to &lt;code class="javascript"&gt;window.onload&lt;/code&gt;. If &lt;code class="javascript"&gt;window.onload&lt;/code&gt; has already been set, a brand new function is created which first calls the original onload handler, then calls the new handler afterwards.&lt;/p&gt;

&lt;p id="p-8"&gt;&lt;code class="javascript"&gt;addLoadEvent&lt;/code&gt; has one very important property: it will work even if something has previously been assigned to window.onload without using &lt;code class="javascript"&gt;addLoadEvent&lt;/code&gt; itself. This makes it ideal for use in scripts that may be executing along side other scripts that have already been registered to execute once the page has loaded.&lt;/p&gt;

&lt;p id="p-9"&gt;I've tested the above code successfully on &lt;acronym title="Internet Explorer"&gt;IE&lt;/acronym&gt; 5, 5.5 and 6 for Windows; &lt;acronym title="Internet Explorer"&gt;IE&lt;/acronym&gt; 5 and Safari for Mac; Opera 7.5 and FireFox on Mac (which should mean it works with those browsers on Windows as well). Opera 6 for Mac failed the test but has poor JavaScript support anyway and is hopefully becoming more and more rare now that Opera 7 has matured.&lt;/p&gt;

&lt;p id="p-10"&gt;I've created &lt;a href="http://simon.incutio.com/code/js/addloadevent/" title="addLoadEvent() test"&gt;a test page&lt;/a&gt; for the function. I'd be interested to here any bug reports from browsers I haven't covered.&lt;/p&gt;

&lt;p id="p-11"&gt;I'm still considering ways in which this technique could be extended to work for generic events rather than just page loads. The challenge there would be to ensure that information about the event itself was passed to the event handlers in a consistent manner. For page load events this isn't an issue as the event object does not contain any valuable information.&lt;/p&gt;

&lt;p id="p-12"&gt;&lt;strong&gt;Update:&lt;/strong&gt; I've written the new technique up &lt;a href="http://www.sitepoint.com/blog-post-view.php?id=171578" title="Closures and executing JavaScript on page load"&gt;on my SitePoint blog&lt;/a&gt; and incorporated an explanation of closures and how they are used to preserve any previously assigned onload handlers.&lt;/p&gt;

&lt;p id="p-13"&gt;&lt;strong&gt;Update 28th May 2006&lt;/strong&gt;: Billy Pan pointed out that the original code caused a runtime error in IE 7. His fix was to add an &lt;code&gt;if (oldonload)&lt;/code&gt;; I have rolled this fix in to the code shown above.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/addloadevent"&gt;addloadevent&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/closures"&gt;closures&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/onload"&gt;onload&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/unobtrusive-javascript"&gt;unobtrusive-javascript&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="addloadevent"/><category term="closures"/><category term="javascript"/><category term="onload"/><category term="unobtrusive-javascript"/></entry></feed>