Thursday, November 20, 2014

Don't repeat expressions in facelets

Have you ever seen repeated EL expressions in JSF like this one?
<h:inputText value="#{oneBean.name}" rendered="#{anotherBean.showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{anotherBean.showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{anotherBean.showPerson ? 'display:block' : 'display:none'}"/>
usw. Another example:
<ui:include src="/include/somesnippet.xhtml">
    <ui:param name="age" value="#{someBean.isMan(person) ? 63 : 60}"/>
    <ui:param name="money" value="#{someBean.isMan(person) and someBean.getCountry(person) eq 'de' ? 1000 : 900}"/>
    <ui:param name="big" value="#{someBean.getCountry(person) eq 'zh' or someBean.getCountry(person) eq 'ru' ? true : false}"/>
</ui:include>
Expressions #{anotherBean.showPerson}, #{someBean.isMan(person)}, #{someBean.getCountry(person)} are repeated multiple times. How to optimize them? Well, you can use JSTL's c:set like this code snippet
<c:set var="showPerson" value="#{anotherBean.showPerson}"/>

<h:inputText value="#{oneBean.name}" rendered="#{showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{showPerson ? 'display:block' : 'display:none'}"/>

<c:set var="man" value="#{someBean.isMan(person)}"/>
<c:set var="country" value="#{someBean.getCountry(person)}"/>

<ui:include src="/include/somesnippet.xhtml">
    <ui:param name="age" value="#{man ? 63 : 60}"/>
    <ui:param name="money" value="#{man and country eq 'de' ? 1000 : 900}"/>
    <ui:param name="big" value="#{country eq 'zh' or country eq 'ru' ? true : false}"/>
</ui:include>
If you are scared about JSTL pitfalls (because you have heard that JSTL is not always JSF friendly :-)), there is an alternative and simple approach - ui:param. TagHandler ui:param uses JSF's VariableMapper to save EL expressions in a map. This map maps EL variables on a page and the EL expressions they are associated with. And here you go:
<ui:param name="showPerson" value="#{anotherBean.showPerson}"/>

<h:inputText value="#{oneBean.name}" rendered="#{showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{showPerson ? 'display:block' : 'display:none'}"/>

<ui:param name="man" value="#{someBean.isMan(person)}"/>
<ui:param name="country" value="#{someBean.getCountry(person)}"/>

<ui:include src="/include/somesnippet.xhtml">
    <ui:param name="age" value="#{man ? 63 : 60}"/>
    <ui:param name="money" value="#{man and country eq 'de' ? 1000 : 900}"/>
    <ui:param name="big" value="#{country eq 'zh' or country eq 'ru' ? true : false}"/>
</ui:include>
The code is more readable, especially if you have very complex and long expressions. Note: we're speaking here about readable code and not about performance optimization because JSF TagHandlers don't evaluate EL expressions.

2 comments:

Note: Only a member of this blog may post a comment.