Enhance the web page look & feel and behavior after it has been loaded – attach onLoad Event Listeners during load

1

Many web applications are rendered by HTML rendering frameworks and technologies such as JSP, JSF, PHP, .NET etc. In such technology stacks, it is common to make use of standard components from 3rd party vendors and open source projects. Such components can typically be configured, customized to a certain extent. However, frequently there will be wish for more extensive customization and refinement, especially when it comes to look & feel in the browser.

Some simple examples:

  • rows in a table should be highlighted when hovered over
  • input items should be visually marked when entered by the user
  • items should be (slightly) repositioned or hidden
  • images, buttons or other elements should be added
  • event triggers should be added to for example perform client side validation or calculation
  • elements should be made draggable or set up as drop target
  • add background images to generated buttons

The list is long and restrained mainly by our own creativity and our project manager’s budget, the latter usually being the most restraining of the two.

While the rendering of the page can not always be effectively or efficiently influenced on the server – there is much we can do in the browser, using JavaScript and DOM Manipulation. However, for such manipulation to take place, the entire page has to be loaded first, otherwise there is no complete DOM model to access and manipulate. That means that many post-load actions should be started from the onLoad event. ....

One way of making that happen is by adding an onLoad attribute to the BODY element of the HTML document and have it call all operations that we want to have performed after loading the page or calling a generic handler that knows which operations are registered to run once load is complete and will do so.

Since we want to limit the modifications to our (server side) page definitions and leverage standard browser functionality as much as possible, we can best achieve registering and executing post load operations without even touching the onLoad attribute itself – we will manipulate it indirectly.

Web browsers – at least of the two most recent generations – allow us to execute JavaScript snippets during the load of the page that register onLoad event listeners. These listeners will be called by the browser once the onLoad event occurs – when the page is completely loaded and ready for manipulation. The listeners are associated with JavaScript functions that will do their job.

Adding such JavaScript snippets to the page can be done by embedding the snippets in the page itself, either in the HEAD or in the BODY section. Alternatively, and often more efficient for generic post load operations, we can simply link a JavaScript library to our page and include the snippets in the JavaScript library.

Note: while the code presented in this article can be used, it is probably much wiser to leverage on of many JavaScript libraries out there to provide this ‘do after load’ operations for us. For example in jQuery – see: http://www.learningjquery.com/2006/09/introducing-document-ready – you can easily schedule actions to be performed after the page has loaded.

A simple example of such a Post Load operation – one that will do the immensely useful task of turning the text on all buttons to uppercase – is discussed next.

Post Load Example – set all button labels to uppercase

Create a JavaScript Library postload.js:

function addLoadListener(fn){<br />    if (typeof window.addEventListener !='undefined')    <br />      window.addEventListener('load',fn,false);<br />    else <br />      if (typeof document.addEventListener !='undefined')    <br />        document.addEventListener('load',fn,false);<br />      else <br />        if (typeof window.attachEvent !='undefined')    <br />          window.attachEvent('onload',fn);<br />        else {<br />          var oldfn=window.onload;<br />          if ( typeof window.onload !='function')    <br />            window.onload=fn;<br />          else    <br />            window.onload = function() { oldfn(); fn();}<br />        }<br />}//addLoadListener<br /><br />function uppercaseButtonLabels() {<br />  // find all buttons <br />  var allBtn = document.getElementsByTagName('button');<br />  for(var n=0;n &lt; allBtn.length;n++){<br />    theBtn = allBtn[n];<br />    // find the childnode of type text<br />    if (theBtn.childNodes.length&gt;0) {    <br />      for(var l=0;l &lt; theBtn.childNodes.length;l++){<br />          var child = theBtn.childNodes[l];<br />          if (child.nodeType==3) // textnode<br />            child.nodeValue= child.nodeValue.toUpperCase();<br />      }// for button childnodes<br />    }//if<br />  }//for buttons<br />}//uppercaseButtonLabels<br /><br />addLoadListener(uppercaseButtonLabels);<br /><br /><br /><br />&nbsp;

Assuming that postload.js is in directory public_html/js of my ADF Faces project, I can include the following link to the JavaScript library in my page definition:

      &lt;afh:head title=&quot;#{nls['TABLE_TITLE_DEPT']}&quot; id=&quot;head&quot;&gt;<br />        &lt;meta http-equiv=&quot;Content-Type&quot;<br />              content=&quot;text/html; charset=utf-8&quot;/&gt;<br />        &lt;script type=&quot;text/javascript&quot; language=&quot;JavaScript&quot;<br />                src=&quot;${pageContext.request.contextPath}/js/postload.js&quot;&gt;&lt;/script&gt;<br />      &lt;/afh:head&gt;<br /><br />

Note: nothing is stopping me from adding page specific post-load operation through JS snippets in the JSF page like this:

        &lt;f:verbatim&gt;<br />          &lt;script type=&quot;text/javascript&quot; language=&quot;JavaScript&quot;&gt;<br />                function postLoadGreeting() {<br />                  alert('Welcome on my page!');<br />                }<br />                <br />                addLoadListener(postLoadGreeting);<br /><br />                &lt;/script&gt;<br />        &lt;/f:verbatim&gt; <br />

as long as it is within the body tag of the page.

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

1 Comment

  1. Good post. I do this to put Google Maps on a page, since the Google Maps API is mostly a Javascript API, with a little bit of REST web service thrown in.