Cleanest way of executing javascript code on page load

Everytime that I work on a new project, I’m always unsure about which way to execute javascript on page load. These are the different techniques :

Your old buddy body.onload()

The safest way to execute javascript when a page loads is to use the body.onLoad method.

  1. <body onload="doSomething();"></body>

The document.ready function with jquery

This technique requires jquery and is similar to the body.onLoad technique (see above).

  1. <body><script>$(document).ready()</script></body>

The problem is that I don’t like that the javascript code is too close to the HTML code. There’s really something that I don’t like.

The #ID.ready

DO NOT USE! It doesn’t work. At first, I tought that this technique worked but in fact, even if the element corresponding to the ID doesn’t exists, the function is called. To understand it better, I’ll give you an example. Suppose that I want to load a user list with ajax after the page load and that list correspond to ul#users, I’d write the following code

  1. $("ul#users").ready(function() {
  2.   loadUsersWithAjax();
  3. });

Unfortunately, it doesn’t work.

The document.ready + #ID.each

After the failure of the #ID.ready technique (see above), I tried a similar thing that is working but ugly looking. Suppose I want to do the same as above, I’d write this :

  1. $(document).ready(function() {
  2.   $("ul#users").each(function() {
  3.       loadUsersWithAjax();
  4.   });
  5. });

That way, it would execute the loadUsersWithAjax() method for each ul#users and because element IDs are unique to a page, the method would be called only once. It looks bad but it’s the “prettiest” way I found of executing javascript code on page load.

Now, I want to know what would you suggest? Which technique is your?

Comments

  1. # Rob December 1, 2008 at 10:52:22

    Sure the JQuery is too close to the HTML in the body. Why not just move it to the HTML head, or a separate JS include?

    $(document).ready(function(){
    loadUsersWithAjax();
    });

  2. # Rob December 1, 2008 at 10:55:36

    I’ll try that code again, escaped:

    <html>
    <head>
    <script>
    $(document).ready(function(){
    loadUsersWithAjax();
    });
    </script>
    </head>
    <body>
    </body>
    </html>

  3. # Dan (maintainer of Javascript Kata) December 1, 2008 at 11:20:55

    Even if the document.ready is in the head of the HTML, it doesn’t change the idea that javascript code and HTML are too coupled. In an MVC way, I’d say that the javascript code should be in the controller but by including it in the view, you can cause problems (and would be anyways anti-MVC).

    Example, suppose the ajax user list (like mentioned in the post) is used on more than one page, it would be more efficient to autoload it whenever the ID is found on that page. That way, you would’nt have to remember to write a document.ready on each page that it’s needed.

    So, it would be better to have it outside the HTML.

  4. # Yansky December 1, 2008 at 12:15:02

    What about http://www.javascriptmvc.com

  5. # Rob December 1, 2008 at 12:37:30

    Script includes get it outside the HTML file:
    <script src=”outside.js”></script>

  6. # Frank December 1, 2008 at 13:16:59

    Rob,

    I think Dan is talking about doing the “on load” thing based on the presence of a HTML element. This gives you the option to put the javascript loading code at one place instead of putting it everywhere where you need to load that list.

  7. # Binny V A December 1, 2008 at 13:43:23

    How about calling the function just before ?


    initFunction()

    That makes sure all the page is loaded before the function is called.

  8. # Dan (maintainer of Javascript Kata) December 1, 2008 at 17:16:59

    @Yansky : I’ll have a look a javascript MVC.

  9. # Dan (maintainer of Javascript Kata) December 1, 2008 at 17:17:26

    @Binny : I don’t understand. Could you be more specific?

  10. # trond December 2, 2008 at 13:43:28

    $(document).ready() is preferable.

    You can’t be sure that body.onload will execute until all elements (incl. external images like banner ads) are loaded into the browser. $(document).ready(), on the other hand, executes *once the HTML DOM is ready for manipulation* (that is, the in-memory representation of the HTML document). Hence, it is safer than (1).

    You should also not put it in your HTML like in your example (in ), but in a separate javascript file which is loaded through (like pointed out by others). Then inside this js-file, add a

    $(document).ready( function() {
    // my stuff
    });

    Another thing you’re confusing, is the use of ready() and each().

    Your last example will load for each one of the elements matched by the selector. In your case I assume it is only one (since you’re using ID), but if your selector were to match more than one element, loadUsersWithAjax() would run once for each of them.

    Best tip: look into the documentation at http://docs.jquery.com/ to understand what each of these really do.

  11. # Dan (maintainer of Javascript Kata) December 2, 2008 at 15:54:27

    @trond
    I worked with each before so I already know when using it and I really don’t like the technique that involves it. It was just like a long strech for what I would want to do. Thus the problem is still existant.

    But thanks anyway, I think I’ve not been clear enough… I’m a bit rusty with this site ;)

  12. # pawel December 3, 2008 at 07:07:36

    In external JavaScript file:

    $(document).ready(function(){

    if( $(’ul#users’)[0] ){
    loadUsersWithAjax();
    }

    });

    I think it does exactly what you want to do: no function calls in HTML document, calling loadUsersWithAjax() when the DOM is ready and only if there’s “ul#users” in the DOM.

  13. # Dan (maintainer of Javascript Kata) December 3, 2008 at 08:19:40

    @pawel Yeah… I think that’s a good solution. Nicer and shorter than the “each” technique. Thanks a lot!

  14. # DevelX December 3, 2008 at 11:13:48

    Hm, well… I prefer this way:
    if (document.addEventListener !== undefined) {
    document.addEventListener(’load’, init, false);
    } else {
    document.attachEvent(’onload’, init);
    }
    This way you cannot make a collision with other scripts using document.load and such. But, well, you need to wait until all images etc are loaded.
    But for the specific usage you need seems pawel’s script good enough.

  15. # Rick F December 8, 2008 at 11:08:08

    Have a look at the jQuery plugin “LiveQuery”. I think it covers some of the cases you mention here.

    http://plugins.jquery.com/project/livequery

  16. # Dan (maintainer of Javascript Kata) December 8, 2008 at 13:34:46

    @Rick F
    Thanks, I think that it’s exactly what I was searching for. I’ll try it and write a post about.

  17. # Maicon Peixinho December 11, 2008 at 06:48:10

    There are other ways that do not require a specific framework for this, such as the function addLoadEvent () “, which is added some methods in the page when all the elements are loaded.

    Example:

    function addLoadEvent(func) {
    if (!isWinLoaded){
    var oldonload = window.onload;
    if (typeof window.onload != ‘function’) {
    window.onload = func;
    } else {
    window.onload = function() {
    if (oldonload) {
    oldonload();
    }
    func();
    }
    }
    }else{
    func();
    }
    }
    PS: “isWinLoaded” is a const set to false on onload of JS.

    Excuse me shift the focus on the topic, but does not taste much of jquery, and therefore, shared a bit of a different note.

    Thank you.

  18. # Learning jQuery December 26, 2008 at 09:57:31

    There is a shorthand alternative to $(document).ready(); Use this shortcut:

    jQuery(function(){
    // your code here
    });

  19. # cancel bubble March 3, 2009 at 13:01:09

    There’s an even shorter alternative with jQuery:

    $(function() {
    // your code here
    });

  20. # Trygve Lie June 11, 2009 at 18:46:20

    Interesting. I’ve been dealing with the same issue in a project which interac heavy with the DOM. I’ve got some limitations in this project which prevents me from using any of the JS libraries out there (so the “ready” function in JQuery are out of the question) and easy injection into a document is a must.

    I ended up writing a small bootstrap script for javascript functions.

    The bootstrap has a array intended to hold functions. Then there is a small “load” function which attach itself to “DOM readyness” and run trought the array of functions and fire the functions in it’s order in the array when the DOM is ready. For the “DOM readyness” detection I use the DOMContentLoaded which are supported in most new sane browsers and a small “hack” (http://javascript.nwbox.com/IEContentLoaded/) for detecting the same “DOM readyness” in IE. This way of detecting “DOM readyness” is pretty much the same way as JQuery and other JS libraries do.

    I did post the bootstrap script with documentation, examples and the source a couple of weeks ago: http://www.trygve-lie.com/blog/entry/bootstraping_javascript

  21. # anthony June 30, 2009 at 01:12:01

    Creating a custom EPiServer property is relatively easy – although I think I’ve not quite got the hang of how to store the actual data. It must be converted to a string for storage in the database. I started to use an XmlSerializer but got confused (mainly as the JavaScript was doing my head in) as to where i should be doing the serialisation. Sadly the only example i could find on the net was how to create a custom property that was a string – about as much use as a chocolate fire guard! So here’s my way of doing it – using a comma separated string (dirty I know!) – please feel free to show me the correct way.
    http://www.casinoszocken.de/

Post a comment

Comments are moderated and innapropriate ones won't be approved. Please respect this public space.