In this article I will demonstrate that there multiple methods for determining the “onLoad” event of you page and discuss which method you should use and when.
<body onload="alert('Hi Marky')">
This caused some issues in itself because it indicated that the HTML was loaded – but did not have any knowledge of the images on the page and they might not have finished downloading – so this was not a reliable way of determining if the page was really loaded.
Then came the Library
If you are including functionality from a Library there is a high probability that the Library is doing some sort of Document Model (DOM) manipulation when the page loads – it has to do this to provide the functionality you are asking it to do.
Take your XPage as a prime example – you are including (well ok the XPage is including) the dojo Library and with that the XSP library built to provide XPage functionality. If you look at the source of an XPage containing a date control you will see this
<input id="view:_id1:_id2:_id39:inputText2" class="xspInputFieldDateTimePicker" type="text" name="view:_id1:_id2:_id39:inputText2" />
But if you look at the HTML created AFTER dojo and the XSP have done their magic the field looks like this!!
<span class="xspInputFieldDateTimePicker" style="display: inline-block;"> </span> <div id="widget_view:_id1:_id2:_id39:inputText2" class="dijit dijitReset dijitInlineTable dijitLeft xspInputFieldDateTimePicker dijitTextBox"> <div class="dijitReset dijitValidationContainer"><input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" tabindex="-1" type="text" value="? " readonly="readonly" /> </div> <div class="dijitReset dijitInputField dijitInputContainer"><input id="view:_id1:_id2:_id39:inputText2" class="dijitReset dijitInputInner" tabindex="0" type="text" value="" /> <input style="display: none;" type="text" name="view:_id1:_id2:_id39:inputText2" /> </div> </div> <span id="view:_id1:_id2:_id39:inputText2_Container" class="xspInputFieldDateTimePicker" style="display: inline-block;"> <span class="dijit dijitReset dijitInline dijitButton xspInputFieldDateTimePicker"> <span class="dijitReset dijitInline dijitButtonNode"> <span id="dijit_form_Button_0" class="dijitReset dijitStretch dijitButtonContents" style="background-image: none; margin: 0px; border: none; padding-left: 0px; background-position: 0% 0%; background-repeat: initial initial;" title=""> <span class="dijitReset dijitInline dijitIcon xspInputFieldDatePickerIcon"> </span> <span class="dijitReset dijitToggleButtonIconChar">?</span> <span id="dijit_form_Button_0_label" class="dijitReset dijitInline dijitButtonText dijitDisplayNone"> </span> </span> </span> <input class="dijitOffScreen" tabindex="-1" type="button" value="" /> </span> </span>
And that doesn’t happen in an instant – it takes time……and if we want to programmatically interact with the “new” date picker code we have to wait for the dojo and XSP to do their thang.
This is where library.onLoad comes into play – it is an event triggered when the library believes that the page is safe to interact with – i.e. everything it needs to do is complete.
The dojo.addOnLoad page explains better than I can
dojo.addOnLoad is a fundamental aspect of using Dojo. Passing addOnLoad a function will register the function to run when the Dom is ready. This differs slightly from document.ready and body.onload in that addOnLoad waits until all dojo.require() (and their recursive dependencies) have loaded before firing.
The XSP is a library built on top of a library and has dependencies on the dojo library.
In our XPage environment we have the onClientLoad event accessible from the XPage event section – this is actually the GUI equivalent to XSP.addOnLoad which is a programmatic function we have available through the XSP library.
jQuery – $(‘document’).ready()
jQuery’s version of this onLoad capability is described as follows:
These people are so much more eloquent that I 🙂
So if everyone fires when the DOM is ready then they should all fire at the same time…right?
Well that is what occurred to me and I wanted to find out – people have told me through the life of this blog that I should always use the XSP.addOnLoad because it fires when the XPage is ready – but if I use jQuery is that ready as well?
It is really not all that complicated to test who fires first – what I created was a variable to track when the page started to load and then asked each library to subtract the time when they fired “when the DOM was ready” and write it to the page. This code sample was added to the top of my XPage so the variable “a” is created immediately when the page is loaded and each library then triggers when it is ready.
and in the onClientLoad event
<xp:this.script><![CDATA[ var e = new Date() document.getElementById('divOnClientLoad').innerHTML = e-a var s=document.createElement('div'); s.innerHTML = "<div>"+"onClientLoad - "+(e-a)+"</div>" document.getElementById('iAmFinished').appendChild(s) ]]> </xp:this.script>
You can see the page I created to test this experiment here
You will see that there are a lot of typeAhead and date picker fields on the page – the reason I did this was to slow down the loading of the page – The libraries were all firing very close together and I wanted to see if I could separate them by delaying the page loading – it didn’t see to make a difference they all fired with the same delay between them.
Well I have to say I was surprised and very glad that I created this experiment because it will change how I determine when the DOM is ready in the future. You can keep testing this for yourself by refreshing the test page above but you will see consistently that the libraries fire in this order:
DOM ready (ms)
As you refresh the page you will see different load times but they are always grouped XSP, clientOnLoad
Why are these different?
Each library determines when they believe the DOM is ready differently – each one is assuming that the DOM is ready when everything is loaded for it’s own library (naturally dojo doesn’t care when jQuery is loaded). For some insight check this StackOverflow post out
From my experiments I noticed that dojo, XSP and onClient load were always no more than 1 milisecond apart and each one of them sometimes came first – i think there is an aspect of the fact that they are all trying to create a DIV and append it to the page (my test code) and that has some nominal time associated with it and they are all trying to append to the same DOM element – for the sake of statistical accuracy my observation is that dojo is usually the first to record a result but because it is not always first I cannot claim that categorically.
I also have to add that there is a discrepancy with the onClientLoad test because it does not use the same variable as the other libraries – because it is being added to the page in a different fashion it is not an identical test. I am not however going to add the whole of the code to the onClientLoad event because then I would be asking the onClientLoad event to trigger the other libraries which isn’t right.
So here is the important things to remember when you are developing your xPage
- Never use dojo.addOnLoad – it fires almost exactly the same time as the XSP but more importantly your xPage XSP library is not ready
- If you are using jQuery *always* use $(‘document’).ready()
- Otherwise use XSP.addOnLoad/onClientLoad
It is interesting to see that jQuery takes longer to be ready and why that is, is way beyond the comprehension of this developer but there is a clear separation and because almost all of my work uses jQuery in one fashion or another I will always use $(‘document’).ready()
Please feel free to argue my experimental methodology if you think it can be improved 🙂