TL;DR – Server-side code in onClientLoad causes a page refresh and prevents additional onClientLoad events with server-side code from running. In this post, I’ll show an example and describe how it behaves.
Page Ready Events
It is extremely useful to have an event trigger that executes when the page is fully loaded; many JavaScript plugins wait for the page to finish loading and then run to activate widgets on the page. Because of its importance, jQuery has $(document).ready()
and Dojo has dojo/domReady
and dojo.addOnLoad()
to make this checking easy.
The Problem with onClientLoad in XPages
XPages provides the onClientLoad
event on pages, custom controls, and panels. XPages allows you to run client-side and/or server-side code in the event. However, running server-side code can cause a tough-to-troubleshoot side effect.
Take, for example, this XPage, which has two panels. Both panels and the page itself have client-side and server-side onClientLoad
code to write a message to the browser console and server console, respectively.
<?xml version="1.0" encoding="UTF-8"?> <xp:view xmlns:xp="http://www.ibm.com/xsp/core"> onClientLoad Event Testing <xp:eventHandler event="onClientLoad" submit="true" refreshMode="norefresh"> <xp:this.script><![CDATA[console.log('Page - onClientLoad');]]></xp:this.script> <xp:this.action><![CDATA[#{javascript:print('Page - onClientLoad');}]]></xp:this.action> </xp:eventHandler> <xp:panel id="panel1"> <xp:eventHandler event="onClientLoad" submit="true" refreshMode="norefresh"> <xp:this.script><![CDATA[console.log('Panel 1 - onClientLoad');]]></xp:this.script> <xp:this.action><![CDATA[#{javascript:print('Panel 1 - onClientLoad');}]]></xp:this.action> </xp:eventHandler> </xp:panel> <xp:panel id="panel2"> <xp:eventHandler event="onClientLoad" submit="true" refreshMode="norefresh"> <xp:this.script><![CDATA[console.log('Panel 2 - onClientLoad');]]></xp:this.script> <xp:this.action><![CDATA[#{javascript:print('Panel 2 - onClientLoad');}]]></xp:this.action> </xp:eventHandler> </xp:panel> </xp:view>
Here’s what happens when the page loads:
- The page-level client-side code runs to write the message to the browser console
- The page-level server-side code runs to write the message to the server console
That’s it.
Execution on onClientLoad
handlers stops at this point because the page has posted to the server because of the server-side code; the onClientLoad
event handlers for the panels do not execute at all.
You can look in the browser’s developer tools and see the POST that is sent. It doesn’t try to update anything on the page, so there’s no response, but it’s still enough to interrupt everything else.
More details on the behavior:
- You can run multiple client-side
onClientLoad
event scripts without issue — as long as they’re not triggering partial refreshes - If the event handlers are rearranged on the page, the one that comes first in the source is the one that will run
- If there is only one
onClientLoad
event with server-side code, it will run (based on it’s order in the source), then POST, then let the rest of theonClientLoad
events on the page that only have client-side code run. (Any with server-side code will not execute — even the client-side event code on handlers that also have server-side code will not run.)
Mitigating the Problem
This may sound like an easy thing to keep in check, but if you have onClientLoad
code on multiple custom controls, it may be hard to make sure that there won’t be a conflict, especially because there won’t be any error thrown.
The strong recommendation is to just not put server-side code in the onClientLoad
event, period.
If you absolutely need it, then you may need a standard of putting any necessary onClientLoad
code in the common layout control that’s loaded on every page, but it still has the potential to interrupt anything else going on the page or annoy the user by causing a delay immediately after the page is loaded waiting for the post and response. I would try to put code in the afterPageLoad
event or use client-side code to trigger an RPC method or custom REST service if server-side code needs to run in that event.
