Quick Tip: Use Dojo Content Panes for Speedier Initial Page Loads
Mon Aug 18 19:12:57 EDT 2014
The XPages Extension Library is full of hidden gems and one I particularly like keeping in my back pocket is the <xe:djContentPane/>
control. It's a fairly unassuming control; like the rest of the components in the "Dojo Layout" category, it takes its name and basic concept from the underlying Dijit. However, you don't have to use it in a full Dojo layout - and, in fact, all of the actual layout types have more-appropriate XSP components. Presumably, its initial use is to load content from a specified URL (via the href
attribute), but I find the partialRefresh
attribute MUCH more interesting. By setting that attribute to true
, you actually carve out a little sub-tree of the page that loads in a separate request from the rest of the page.
That's "loads" in the JSF sense: any of the properties - including ${...}
-bound ones - of any component inside of the content pane aren't evaluated until that second request. So what's the upshot of this? If the values inside are particularly expensive, such as heavy database access or a remote API, the rest of the page will load first and then the content pane's area will be a loading message until it finishes.
This tool comes in handy even if you don't touch a single other piece of Dojo UI. The content pane by default is just a <div/>
, and you're free to replace the loading message. For example, to Bootstrap-ify it:
<xe:djContentPane id="timeEntriesPane" partialRefresh="true"> <xp:this.loadingMessage><![CDATA[ <div style="padding: 1em; text-align: center"><i class="icon-spinner icon-spin green bigger-200"></i></div> ]]></xp:this.loadingMessage> ... </xe:djContentPane>
(That snippet is from a pane that loads open client time entries from FreshBooks, hence the id
)
The nicest part is that using this technique is often just as simple as wrapping your content in the control and switching the attribute. There are only a few situations I've run into in regular use that require some consideration:
-
If you have some on-load client-side JavaScript that should operate on the contents, such as dojo.behavior. In that case, you can use the
onDownloadEnd
event (if I recall correctly) to trigger the behavior. You could likely set this via a theme (it's available as both a normal "Event" as well as an attribute on the tag). -
If the code inside is dependent on query string parameters. Parameters are not included in the partial-refresh URL. I don't recommend the specific suggestion of dumping all query parameters into
viewScope
(that's asking for an injection vulnerability); instead, make sure that anything you get from the query string is either "baked into" the loading of the rest of the page (say,documentId="${param.documentId}"
on a document data source instead ofdocumentId="#{param.documentId}"
) or added via a data context (e.g.<xp:dataContext var="someParamHolder" value="${param.someParam}"/>
). - If the content of the pane is error-prone. The partial refresh masks the error message (this may actually be preferable from a UI perspective): you just get an "error loading contents" message on the page. To see the normal stack trace, you have to either disable partial refresh or check the Network pane of your browser's debug tools.
With those in mind: give it a try! Used in the right situation, you can get a nice little boost of initial page load with only a little cost in overall load time - it can make for a surprisingly-better experience.