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?

  • Leo
    How about just moving the javascript to the bottom of the page?
  • anthony
    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/
  • 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
  • There's an even shorter alternative with jQuery:

    $(function() {
    // your code here
    });
  • There is a shorthand alternative to $(document).ready(); Use this shortcut:

    jQuery(function(){
    // your code here
    });
  • Maicon Peixinho
    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.
  • Dan
    @Rick F
    Thanks, I think that it's exactly what I was searching for. I'll try it and write a post about.
  • Rick F
    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
  • DevelX
    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.
  • Dan
    @pawel Yeah... I think that's a good solution. Nicer and shorter than the "each" technique. Thanks a lot!
  • pawel
    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.
  • Dan
    @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 ;)
  • $(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.
  • Dan
    @Binny : I don't understand. Could you be more specific?
  • Dan
    @Yansky : I'll have a look a javascript MVC.
  • How about calling the function just before ?

    ...
    initFunction()



    That makes sure all the page is loaded before the function is called.
  • Frank
    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.
  • Rob
    Script includes get it outside the HTML file:
    <script src="outside.js"></script>
  • Yansky
  • Dan
    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.
  • Rob
    I'll try that code again, escaped:

    <html>
    <head>
    <script>
    $(document).ready(function(){
    loadUsersWithAjax();
    });
    </script>
    </head>
    <body>
    </body>
    </html>
  • Rob
    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();
    });
blog comments powered by Disqus