Quantcast
Channel: XPages – Xcellerant
Viewing all articles
Browse latest Browse all 216

XPages Tip: Beware Server-Side code in Multiple onClientLoad Events

$
0
0

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:

  1. The page-level client-side code runs to write the message to the browser console
  2. 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 the onClientLoad 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.



Viewing all articles
Browse latest Browse all 216

Trending Articles