Monday, October 07, 2013

The Empty JSF Component

JSF 2 was the much needed improvement on top of its predecessor. Most notable of its features was the Facelets view declaration language which, amongst various other things, allowed mixing HTML and JSF components together in the same file. A direct impact of this capability, was the ease with which a developer could translate HTML files in to functioning XHTML code.

But then again, every now and then there would be this case where you need to set a rendered condition for a HTML element - like menu items or some thing represented using a <li> tag - which does not have any equivalent component in JSF. The most common way of handling such a situation is via the <c:if/> tags. Not a very elegant looking solution, but it works.

Now if you, like me, are not a big fan of using the JSTL functions, then the chances are that you might have wondered, "Why doesn't standard JSF just provide an empty JSF component that just had one attribute and only one attribute - a rendered condition!"

Well, fret not, things are looking brighter. In the latest release, JSF 2.2, the FacesComponent annotation got a make over with the addition of 3 new attributes:
  • createTag - If set to true the component will be directly useable via a tag on a Facelet. 
  • tagName - Optional explicit name for the tag. If omitted, the class’ simple name with the first character in lowercase will be used. 
  • namespace - Optional explicit namespace for the tag. If omitted the namespace ‘http://xmlns.jcp.org/jsf/component’ will be used. 

, meaning you can create this empty JSF component with code as simple as the following:

@FacesComponent(value = "group", createTag = true, tagName = "group")
public class GroupComponent extends UIComponentBase
{
    @Override
    public String getFamily()
    {
        return "Rogue.IO";
    }
}

Next, you can use this new empty component in your Facelet page as shown below:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:r="http://xmlns.jcp.org/jsf/component">
    <!-- Adaptation of the bootstrap based drop down menu -->
    <r:group rendered="#{menu.has.children}">
        <li class="dropdown">
            <a href="#" class="dropdown-toggle"
                        data-toggle="dropdown">
                #{menu.name} <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
                <ui:repeat value="#{menu.children}" var="child">
                    <li>
                        <a href="#">#{child.name}</a>
                    </li>
                </ui:repeat>
            </ul>
        </li>
    </r:group>
    <r:group rendered="#{not menu.has.children}">
        <li>
            <a href="#">#{menu.name}</a>
        </li>
    </r:group>
</ui:composition>

No more JSTL hacks. Hope this was useful to you.

No comments: