Sunday 21 September 2014

Input in uppercase with JSF inputText, a TagHandler example

Introduction

Recently there was a requirement from a client to be able to input data all in uppercase within a JSF web application.

When you write a simple JSF converter and add a CSS style class to the component to uppercase all input client side, you’re done. You can find various posts on the internet where this solution is described.

This blog shows how you can improve the solution.  You can create a JSF tagHandler which allows you to combine the adding of the converter and CSS style class, by defining your custom tag.
It is convenient and typesafe.  Typesafe Because it is a tag, so you have IDE autocompletion.  Within the name of the converter and the CSS style class name, you can make some typos which leads to an incorrect behaviour.

TagHandler

What is a JSF TagHandler? The tagHandler is some piece of code executed when JSF encounters your custom tag that you have placed in the xhtml page.  This code runs during the creation of the JSF component tree and thus ideal to tweak some components as we like to do for the uppercase scenario.

Your tagHandler should extend from the javax.faces.view.facelets.TagHandler JSF class.  And all your work should go into the apply method.  This method is called in response to the identification of your custom tag in the xhtml file.

This method has a UIComponent typed parameter representing the parent component your custom tag belongs to.  So adding a converter and style class to your inputText component is very straightforward:

public class UppercaseHandler extends TagHandler { 
 
    public UppercaseHandler(TagConfig config) { 
        super(config); 
    } 
 
    @Override 
    public void apply(FaceletContext ctx, UIComponent parent) throws IOException { 
        if (parent instanceof HtmlInputText) { 
            HtmlInputText inputText = (HtmlInputText) parent; 
            inputText.setConverter(new UppercaseConverter()); 
 
            String styleClass = inputText.getStyleClass(); 
            if (styleClass == null) { 
                styleClass = ""; 
            } 
            if (!styleClass.contains("uppercase")) { 
                inputText.setStyleClass(styleClass + " uppercase"); 
            } 
        } 
    } 
} 

Configuration

The next step we have to do, is define the name of our custom tag and link the tagHandler class to it. This is done in the Facelets configuration file. Here you can define your new tag name and the tagHandler class name which is associated with it.

<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" 
                version="2.0"> 
    <namespace>http://www.c4j.be/rubus</namespace> 
 
    <tag> 
        <tag-name>uppercase</tag-name> 
        <handler-class>be.sezz.handler.UppercaseHandler</handler-class> 
    </tag> 
 
</facelet-taglib>

In other scenarios, you can assign tags to converters, custom defined components or user defined EL functions.

Example

In the Facelets Configuration file, we have defined a namespace(http://www.c4j.be/rubus in the example above)  This namespace we can be used in the xhtml file and our custom tag can be used. An example could be.

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:r="http://www.c4j.be/rubus"> 
 
... 
 
<h:body> 
    <h:form id="mainForm"> 
        <h:inputText id="field" value="#{someBean.value}"> 
            <r:uppercase/> 
        </h:inputText> 
    </h:form> 
</h:body> 
</html> 

Conclusion

The JSF TagHandler is a very convenient way of assigning a tag name to some custom functionality you have created.  Better because it is ‘typesafe’ and thus you get warned when you should make a typo.
In the example above, you saw how you can assign in a few lines a custom converter and CSS style class to a JSF inputText component.