Search code examples
jsf-2jstlfacelets

Replace <c:if> and fn:toUpperCase() with JSF-tags


This example is from a book on JSF. The excercise is to refactor the following Facelets code while eliminating <c:if> and fn:toUpperCase(). Usage of <c:forEach> is allowed.

#{myBean.numbers} returns String["one","two","three"]

As the book is on JSF and not on Java, I suppose the existing Java-code is not to be touched. But I can't think of another way to do this solely in Facelets.

<c:forEach var="item" items="#{myBean.numbers}">
    <c:if test="#{not fn:endsWith(item,'o')}">
        #{item}
    </c:if>
    <c:if test="#{fn:endsWith(item,'o')}">
        #{fn:toUpperCase(item)}
    </c:if>
</c:forEach>

Only thing I can think of is using a converter that conditionally uses String#toUpperCase() and then I still do not understand why use of <c:forEach> should still be allowed:

<ui:repeat var="item" value="#{myBean.numbers}">
     <h:outputText value="#{item}" converter="conditionalConverter"/>
</ui:repeat>

Is there a more "Facelets way" to do this (and still a need to use <c:forEach>)?

UPDATE: Instead of <c:if> one could still use e.g. <h:outputPanel> and it's rendered-attribute, but there is still no Java-less replacement for fn:toUpperCase().

I am asking for learning purposes only. I suppose the <ui:repeat>-solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?


Solution

  • As to <c:if>, the JSF alternative to JSTL <c:if> is the rendered attribute on any component. For example, <h:panelGroup> or <h:outputText>. Those components doesn't generate additional markup if there are no attribtues specified which should end up in HTML, like id or styleClass, otherwise they generate a <span>.

    Here's an example of both:

    <h:panelGroup rendered="#{not fn:endsWith(item,'o')}">
        #{item}
    </h:panelGroup>
    <h:outputText value="#{fn:toUpperCase(item)}" rendered="#{fn:endsWith(item,'o')}" />
    

    As to fn:toUpperCase(), JSF has no alternative. I'm not sure why you would need a JSF alternative as it's essentially not a tag, but a simple EL function which is perfectly usable in both JSTL and JSF tags. In any case, you could if necessary throw in CSS text-transform: uppercase. As this takes place entirely client side, your only problem may be the browser support.

    <h:outputText value="#{item}" style="text-transform: uppercase" />
    

    (note: this is just an example, the normal practice is to put styles in its own .css file which you load by <h:outputStylesheet>)

    <h:outputText value="#{item}" styleClass="uppercased" />
    

    I suppose the -solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?

    I'm a big fan of "Use the right tool for the job". Use JSTL tags to conditionally build the JSF component tree. Use JSF components to generate HTML. That's it. See also JSTL in JSF2 Facelets... makes sense?