One of the biggest impacts on performance is the rendered property of components. As I’ve blogged about before, it’s calculated multiple times during a partial refresh. If the rendered property is computed using Expression Language (e.g. #{viewScope.showTheseFields}
), the impact is probably not very high: the check goes through the VariableResolver to identify the Java object relating to what’s to the left of the “.”, then through the PropertyResolver to identify and retrieve the property to the right of the “.” If it’s referencing a dataContext, (e.g. #{showFields}
), it just has to hit the VariableResolver.
But some properties are not available via Expression Language, e.g. whether or not a dominoDocument datasource is in edit mode. #{document1.editable}
doesn’t map to the isEditable()
method. So SSJS is required.
When SSJS is needed, one of the biggest enhancements since 8.5.0 to improve the performance of the rendered property has been view.isRenderingPhase()
. This means the code only runs during the Render Response phase. So that’s what I add by default wherever possible.
But there are times you can try to be too clever and cause problems.
Recently I’ve been working on an application that I hope will become the basis of an upcoming blog series. So I set the rendered properties of the Save button as #{javascript:if (view.isRenderingPhase()) document1.isEditable()}
and for the corresponding Edit button #{javascript:if (view.isRenderingPhase()) !document1.isEditable()}
. The Save button worked fine. But the Edit button didn’t. I tried changing it to run SSJS, got no errors, but the button didn’t work. I tried adding a print() statement at the start of the SSJS, but that wasn’t triggered.
It seems that when not in the Render Response phase, the rendered property was returning false – because nothing was set. But that meant the eventHandler’s HTML was pushed to the browser in Render Response, but the eventHandler was not available in the other phases, so the SSJS did not trigger.
Lesson learned, and although it’s a bit longer, the code for the Edit button’s rendered property was changed to #{javascript:(view.isRenderingPhase()) ? !document1.isEditable() : true}
. So it’s not just hardcoded to true for every other phase.
NOTE: On reflection, just having document1.isEditable()
is probably not much worse for performance than view.isRenderingPhase()
then return true
. Troubleshooting why the eventHandler wasn’t triggering, however, had a much bigger impact on my performance. Lesson two is don’t waste time getting every millisecond of performance out of an application: you might spend more time troubleshooting, and network performance is likely to have a bigger impact on the application’s performance!
To check the the edit mode of a datasource in EL you could try #{!view.data[0].readonly}.
The equivalent of the button’s SSJS should be something like #{view.renderingPhase?view.data[0].readonly:true} (if it is the first datasource on your XPage).
Hi Paul,
Thanks for sharing.
Since time ago, I use the next “snippet” for hide/show elements depending on the document.isEditable property
– A DataContext inside the panel where the documentDataSource is, with the next value:
…..
– Then, when I need to show / hide an element, just with the next simple EL works fine:
….
or
….
In this way we keep the XML simple, readable, and the performance is quite good.
Regards,
Txemanu
I paste the code again:
– A DataContext inside the panel where the documentDataSource is, with the next value:
(xp:panel)
(xp:this.dataContexts)
(xp:dataContext var=”isEditable” value=”#{javascript: xspDoc.isEditable();}”)(/xp:dataContext)
(/xp:this.dataContexts)
(xp:this.data)
(xp:dominoDocument var=”xspDoc” ….. /)
(/xp:this.data)
…..
– Then, when I need to show / hide an element, just with the next simple EL works fine:
(xp:scriptBlock rendered=”#{isEditable}”)….
or
(xp:scriptBlock rendered=”#{not isEditable}”)….
A dataContext on a Panel is a good approach. I’m not sure if it’s still the case, but in 8.5.3 rendered property on a dataContext associated to a Panel recalculated fewer times than one associated to an XPage or Custom Control itself.