Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Craft Ajax applications using JSF with CSS and JavaScript, Part 2: Dynamic JSF forms

Explore JavaScript support in standard JSF components

Andrei Cioroianu, Senior Java Developer and Consultant, Devsphere
Andrei Cioroianu is the founder of Devsphere, a provider of Java EE development and Ajax/JSF consulting services. He's been using Java and Web technologies since 1997 and has 10 years of professional experience in solving complex technical problems and managing the full life cycle of commercial products, custom applications, and open source frameworks. You can reach Andrei through the contact form at devsphere.com.

Summary:  In the first article of this two-part series, author and Java™ developer Andrei Cioroianu showed how to use the style attributes of JavaServer Faces (JSF) components and how to set up default values for those attributes. In this second installment of the series, learn how to exercise the JavaScript-related attributes of standard JSF components. Learn several Web techniques based on the Document Object Model (DOM) APIs, JavaScript, and Cascading Style Sheets (CSS). See how to hide and display optional JSF components without refreshing a Web page, how to implement client-side validation that is executed in the Web browser, and how to develop a custom component that displays help messages for the input elements of a Web form.

View more content in this series

Date:  12 Feb 2008
Level:  Advanced PDF:  A4 and Letter (164KB | 23 pages)Get Adobe® Reader®
Also available in:   Chinese  Japanese  Vietnamese

Activity:  25817 views
Comments:  

Handling events and updating the user interface

Many JSF HTML components have JavaScript-related attributes that let you specify code fragments, which are executed in the Web browser when a certain UI event happens. For example, there are seven types of mouse events supported by standard JSF components:

  • onmouseover
  • onmouseout
  • onmousemove
  • onmousedown
  • onmouseup
  • onclick
  • ondblclick

When a UI component gains or loses the keyboard focus, it generates events that can be captured through the onfocus and onblur attributes. The onkeydown, onkeyup, and onkeypress events are fired when a key is pressed or released. In addition, the <h:form> component accepts the onsubmit and onreset attributes, and the input components have the onchange and onselect attributes, which can be used to call a JavaScript function when the form element's state changes.

You can also use JavaScript-related attributes of the HTML elements that are directly included in a JSF page instead of being rendered by JSF components. For example, the <body> tag has the onload and onunload attributes. The onload event is fired when the loading of a page is completed in the Web browser. The onunload event occurs when the user leaves the page.

A typical JavaScript event handler uses DOM APIs in the Web browser to update the properties of the HTML elements rendered by JSF components. You can easily locate the objects representing the HTML elements using the DOM Core API. For example, you can use document.getElementById(...) to find an element whose ID is known.

The DOM HTML API extends the DOM Core API, adding methods and properties specific to HTML documents. Use document.forms.myFormId to get the object representing a form in the Web browser, and then obtain an array of objects representing the form's elements with myForm.elements. A very useful property is className, which allows you to change the class attribute of an HTML element.

The DOM HTML specification (see Resources) describes all standard properties and methods of the objects representing elements of a page on the client side. Most Web browsers, including IE, Firefox, Netscape, Safari, and Opera, support additional properties, such as innerHTML, which let you change the contents of an HTML element.

The examples in this section show how to use the JavaScript-related attributes of JSF HTML components and how to update the user interface using the DOM HTML API.

Placing scripts within JSF pages

JavaScript code can be inserted in a JSF page as in any regular Web page, using the <script> element of HTML (see Listing 1). You could use JavaScript code to generate HTML content with document.write() in the Web browser, but this is rarely needed. In most cases, you will place the <script> elements within the page's header, which will contain the JavaScript functions called from the event attributes, such as onclick, onsubmit, and onchange. You can also use the <noscript> element to warn users if JavaScript is disabled in their browsers.


Listing 1. Using the <script> tag
<html>
    <head>
        <script type="text/javascript">
            function myEventHandler(...) {
                ...
            }
        </script>
    </head>
    <body>
        <noscript>
            This page requires JavaScript.
        </noscript>
        ...
    </body>
</html>

Apache MyFaces Tobago

If you prefer using JSF components instead of HTML tags, you could use the <tc:script> component of MyFaces Tobago, which renders the <script> element for you.

Place your JavaScript code in .js files if you want to call the same functions in multiple pages. External scripts must be imported in the Web pages, using the src attribute of the <script> tag (see Listing 2). In this case, make sure the /faces/ prefix isn't added to the script's URL, which can happen if you use a relative URI within the src attribute. The simplest way to avoid this issue is to use the .faces suffix. If you prefer the /faces/ prefix for requesting JSF pages, specify an absolute URI for the JavaScript file, including the context path within the src attribute of the <script> tag.


Listing 2. Importing external scripts
<script type="text/javascript"
    src="${pageContext.request.contextPath}/scripts/MyScript.js">
</script>
<script type="text/javascript"
    src="<%=request.getContextPath()%>/AnotherScript.js">
</script>

Hiding and displaying optional JSF components

In Part 1 of this series, you saw how to set the style classes of JSF components on the server side by using the styleClass attribute. You can also set or change style classes on the client side by using JavaScript and DOM. The following example shows how to collapse and expand a group of optional components using the display CSS property. A simple search form (see Figure 1) contains a required text field, two check boxes, and a drop-down list. When the user checks More Options, the panel containing the Match Case and Language components is displayed. If the user unchecks More Options, the optional components are collapsed.


Figure 1. SearchForm example
SearchForm example

The SearchForm.jsp example (see Listing 3) uses standard JSF components to build the Web from. The optional components are placed within a <h:panelGrid> container which is rendered as an HTML table. The optional panel is made visible or hidden on the client side using a JavaScript function named updatePanelClass(). As its name indicates, this function changes the style class of the <table> element rendered by <h:panelGrid>. The updatePanelClass() function is invoked every time the user changes the status of the check box labeled More Options because the updatePanelClass() call is coded within the onclick attribute of the <h:selectBooleanCheckbox> component.


Listing 3. The SearchForm.jsp example
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<f:view>
<html>
<head>
    <title>Search Form</title>
    ...
</head>
<body onload="initForm()">
    <h1>Search Form</h1>
    <h:form id="searchForm">
        <h:panelGrid columns="1" border="0" cellspacing="5">
            <h:panelGroup>
                <h:outputLabel value="Text: " for="text"/>
                <h:inputText id="text" value="#{searchBean.text}"
                    required="true" requiredMessage="Required" size="20"/>
                <h:message for="text"/>
            </h:panelGroup>
            <h:panelGroup>
                <h:selectBooleanCheckbox id="moreOptions"
                    value="#{searchBean.moreOptions}"
                    onclick="updatePanelClass()"/>
                <h:outputLabel value="More Options" for="moreOptions"/>
            </h:panelGroup>
            <h:panelGrid id="optionsPanel"
                    columns="1" border="0" cellspacing="5">
                <h:panelGroup>
                    <h:selectBooleanCheckbox id="matchCase"
                        value="#{searchBean.matchCase}"/>
                    <h:outputLabel value="Match Case" for="matchCase"/>
                </h:panelGroup>
                <h:panelGroup>
                    <h:outputLabel value="Language: " for="language"/>
                    <h:selectOneMenu id="language" value="#{searchBean.language}">
                        <f:selectItem itemValue="English" itemLabel="English"/>
                        <f:selectItem itemValue="Spanish" itemLabel="Spanish"/>
                        <f:selectItem itemValue="French" itemLabel="French"/>
                    </h:selectOneMenu>
                </h:panelGroup>
            </h:panelGrid>
            <h:commandButton id="search" value="Search"
                action="#{searchBean.searchAction}"/>
        </h:panelGrid>
    </h:form>
</body>
</html>
</f:view>

The HTML produced by the SearchForm.jsp page is shown in Listing 4. Observe how the standard JSF components add the searchForm: prefix to the IDs of the HTML elements rendered by the components nested within the JSF form whose ID is searchForm.


Listing 4. HTML produced by the SearchForm.jsp
<html>
<head>
    <title>Search Form</title>
    ...
</head>
<body onload="initForm()">
    <h1>Search Form</h1>
    
<form id="searchForm" name="searchForm" method="post" 
    action="/jsf12js/SearchForm.faces" 
    enctype="application/x-www-form-urlencoded">
...
<table border="0" cellspacing="5">
<tbody>
<tr>
<td><label for="searchForm:text">Text: </label>
<input id="searchForm:text" type="text" 
    name="searchForm:text" size="20" /></td>
</tr>
<tr>
<td><input id="searchForm:moreOptions" type="checkbox" 
    name="searchForm:moreOptions" checked="checked" 
    onclick="updatePanelClass()" />
<label for="searchForm:moreOptions">More Options</label></td>
</tr>
<tr>
<td><table id="searchForm:optionsPanel" border="0" cellspacing="5">
<tbody>
<tr>
<td><input id="searchForm:matchCase" type="checkbox" 
    name="searchForm:matchCase" />
<label for="searchForm:matchCase">Match Case</label></td>
</tr>
<tr>
<td><label for="searchForm:language">Language: </label>
<select id="searchForm:language" name="searchForm:language" size="1">
    <option value="English">English</option>
    <option value="Spanish">Spanish</option>
    <option value="French">French</option>
</select></td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td><input id="searchForm:search" type="submit" 
    name="searchForm:search" value="Search" /></td>
</tr>
</tbody>
</table>
...
</form>
</body>
</html>

Listing 5 shows the <style> element of the SearchForm.jsp page whose header contains both style classes and JavaScript functions. The visible class just sets the left margin of the optional panel and doesn't need any other settings because the HTML table is displayed by default. The hidden class sets the display CSS property to none, turning off the display of the table.


Listing 5. The style classes of SearchForm.jsp
<style type="text/css">
    .visible { margin-left: 40px; }
    .hidden  { display: none; }
</style>

The updatePanelClass() function (see Listing 6) locates the searchForm:moreOptions checkbox and the searchForm:optionsPanel table with document.getElementById(). The panel object represents the <table id="searchForm:optionsPanel"> element rendered by <h:panelGrid id="optionsPanel">, and the checkbox object represents the <input id="searchForm:moreOptions"> element rendered by <h:selectBooleanCheckbox id="moreOptions">. The updatePanelClass() function gets the status of the checkbox object from the checked DOM property and sets the style class of the panel table, using the className DOM property.


Listing 6. The updatePanelClass() function of SearchForm.jsp
function updatePanelClass() {
    var checkbox = document.getElementById("searchForm:moreOptions");
    var panel = document.getElementById("searchForm:optionsPanel");
    panel.className = checkbox.checked ? "visible" : "hidden";
}

The header of the SearchForm.jsp page also contains the initForm() function (shown in Listing 7) whose call is coded within the onload attribute of the <body> element. This function locates the text field of the form and calls focus(), so that when the page is loaded in the browser, the user can start entering the text without having to click the component first. Then, initForm() calls updatePanelClass() to initialize the optional panel's class.


Listing 7. The initForm() function of SearchForm.jsp
function initForm() {
    var text = document.getElementById("searchForm:text");
    text.focus();
    updatePanelClass();
}

The values of the input components from the SearchForm.jsp example are bound to the properties of a simple bean, and the Search button triggers an action method named searchAction(). The code of the SearchBean class is shown in Listing 8.


Listing 8. The SearchBean class
package jsfcssjs;

public class SearchBean implements java.io.Serializable {
    private String text;
    private boolean moreOptions;
    private boolean matchCase;
    private String language;
    
    public SearchBean() {
    }
    
    public String getText() {
        return text;
    }
    
    public void setText(String text) {
        this.text = text;
    }

    ...

    public String searchAction() {
        System.out.print("Text: " + text);
        if (moreOptions) {
            if (matchCase)
                System.out.print(", Match Case");
            System.out.print(", Language: " + language);
        }
        System.out.println();
        return null;
    }
    
}

Implementing client-side validation

The JSF framework provides several validators that run on the server side. When a JSF validator finds an error, the form is returned to the user so he or she can correct it. To minimize the failed form submissions, you can use JavaScript code to verify the user input on the client side, too. The following example shows how to test the maximum length of the data entered in a text-area component. The current length is also shown as the user types the text. When the user clicks the Submit button, a JavaScript function is used to verify the input.


ClientValidation example

Using the maxlength attribute

The <h:inputText> component allows you to limit the length of the entered data with the maxlength attribute. Unlike the single-line input field, the multi-line <h:inputTextarea> component doesn't have a maxlength attribute because the rendered <textarea> tag of HTML doesn't support it.

The JSF form of the ClientValidation.jsp example (see Listing 9) contains a <h:inputTextarea> component that uses the onkeyup attribute, so a JavaScript function named validateText() is called every time the user presses a key. This function is also invoked once the page is loaded in the browser because the onload attribute of the <body> tag contains the validateText() call. Even if the user input is validated on the client side, the <h:inputTextarea> component uses the required attribute and the <f:validateLength> validator to verify the entered text on the server-side, too—just in case JavaScript is disabled in the user's browser. Server-side validation is also necessary to defend against malicious users.


Listing 9. The ClientValidation.jsp example
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<f:view>
<html>
...
<body onload="validateText()">
    <h1>Client-Side Validation</h1>
    <h:form id="validForm" onsubmit="return validateForm()">
        <h:panelGrid columns="1" border="0" cellspacing="5">
            <h:panelGroup>
                <h:outputText value="Text (max #{textBean.maxLength} chars): "/>
                <f:verbatim><span id="charCount"></span></f:verbatim>
            </h:panelGroup>
            <h:panelGroup>
                <h:inputTextarea id="textArea" value="#{textBean.text}"
                        required="true" rows="5" cols="30"
                        onkeyup="validateText()">
                    <f:validateLength maximum="#{textBean.maxLength}"/>
                </h:inputTextarea>
                <h:message for="textArea"/>
            </h:panelGroup>
            <h:commandButton id="submit" value="Submit"
                action="#{textBean.submitAction}"/>
        </h:panelGrid>
    </h:form>
</body>
</html>
</f:view>

The validateText() function (shown in Listing 10) locates the page's form with document.forms.validForm and gets the object representing the text area with form.elements["validForm:textArea"]. Then, the JavaScript code tests the length of the entered text and returns an error message if the user input isn't valid. In addition, validateText() shows the current length by setting the innerHTML property of the <span id="charCount"> element from ClientValidation.jsp. The style class is also updated, using the className DOM property of the span element.


Listing 10. The validateText() function of ClientValidation.jsp
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<f:view>
<html>
<head>
    <title>Client-Side Validation</title>
    <style type="text/css">
        .valid { color: green; }
        .error { color: red; }
    </style>
    <script type="text/javascript">
        function validateText() {
            var form = document.forms.validForm;
            var textArea = form.elements["validForm:textArea"];
            var length = textArea.value.length;
            var maxLength = <h:outputText value="#{textBean.maxLength}"/>;
            var error = null;
            if (length == 0)
                error = "Text cannot be empty.";
            else if (length > maxLength)
                error = "Text cannot have more than "
                    + maxLength + " characters."
            var span = document.getElementById("charCount");
            span.innerHTML = length;
            span.className = (error == null) ? "valid" : "error";
            return error;
        }
        ...
    </script>
</head>
...
</html>
</f:view>

The maxLength variable is initialized in the JavaScript code from Listing 10, using the property with the same name of a bean whose ID is textBean. The value of this property is specified in the faces-config.xml file (see Listing 11).


Listing 11. Configuring TextBean in faces-config.xml
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" ... version="1.2">

    <managed-bean>
        <managed-bean-name>textBean</managed-bean-name>
        <managed-bean-class>jsfcssjs.TextBean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>maxLength</property-name>
            <value>100</value>
        </managed-property>
    </managed-bean>
    ...
</faces-config>

The ClientValidation.jsp example contains a second JavaScript function named validateForm() (see Listing 12). This function is invoked when the Submit button is clicked. Observe the return keyword used within the onsubmit attribute of <h:form>, right before the validateForm() call. If the returned value is false, meaning that the user input isn't valid, the Web browser doesn't submit the form data to the server. This is the desired result because validateForm() signals the error to the user with alert(), and there is no point to submit the invalid input.


Listing 12. The validateForm() function of ClientValidation.jsp
function validateForm() {
    var error = validateText();
    if (error)
        alert(error);
    return error == null;
}

If the user input is valid, validateForm() returns true and the Web browser submits the form data to the server where the JSF framework invokes the submitAction() method of the TextBean class (see Listing 13).


Listing 13. The TextBean class
package jsfcssjs;

public class TextBean implements java.io.Serializable {
    private String text;
    private int maxLength;
    
    ...

    public String submitAction() {
        System.out.println("Length: " + text.length());
        return null;
    }

}

The maximum length validation implemented above for the <h:inputTextarea> component is coded within the ClientValidation.jsp example. This was the simplest way to do it, but the code is not reusable without changes. When implementing features that are not specific to a particular page, it is a good idea to move the JavaScript code into external .js files so you can call their functions from any page of the application. In addition, you can develop custom JSF components to set up JavaScript-based mechanisms, and you can even add custom attributes to the existing components. The next section shows how to implement generic UI features that enhance the standard JSF components.

Using custom attributes to enable new UI features

Part 1 of this series showed you how to build a custom component for setting the default styles of JSF components. In this section, you'll see how to use the same technique for setting JavaScript-related attributes. In addition, the samples presented here use a custom attribute, which is added with the <f:attribute> tag to standard JSF components.

Developing the custom JSF component

Next, you'll see how to build a custom component that modifies the onfocus and onblur attributes of every nested component that contains <f:attribute name="helpOnFocus" value="..."> (see Listing 14). The JavaScript expressions of the onfocus and onblur attributes are evaluated in the Web browser when a form element gains and loses the keyboard focus. The custom component, whose tag is named <js:helpOnFocus>, changes the onfocus attribute of each nested input component to show a help message within a <div id="helpOnFocus"> element when the rendered <input> element gains the focus. The onblur attribute of the nested component is also changed to clear the help message when the <input> element loses the keyboard focus.


Listing 14. Using the <js:helpOnFocus> component in a JSF page
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<%@ taglib prefix="js" uri="/js.tld" %>
...
<script type="text/javascript" src=".../HelpOnFocus.js">
</script>
...
<js:helpOnFocus>
    ...
    <h:inputText ...>
        <f:attribute name="helpOnFocus" value="... Help message ..."/>
    </h:inputText>
    ...
</js:helpOnFocus>
...
<div id="helpOnFocus">
</div>
...

The SetupComponent class, which was presented in Part 1, traverses the JSF component tree, allowing you to change the attributes of the nested components right before their rendering. The HelpOnFocusComponent class (see Listing 15) extends SetupComponent and implements the setup() method, which is called for every nested component whose rendered property is true. The getAttribute() method retrieves the value of a single attribute from the component's attribute map. The insertCall() method includes a function call within the given attribute, preserving any existing value. Nothing is done if the attribute already contains the function call, which happens when the application returns the same form to the user after a post. In this case, the custom component has already added the onfocus and onblur attributes to the nested components during the processing of a previous request. The attributes already contain the JavaScript calls because the JSF framework saves the state of all components between requests.


Listing 15. The HelpOnFocusComponent class
package jsfcssjs;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import java.util.Map;

public class HelpOnFocusComponent extends SetupComponent {

    protected void setup(FacesContext ctx, UIComponent comp) {
        Map<String, Object> attrMap = comp.getAttributes();
        String helpOnFocus = getAttribute(attrMap, "helpOnFocus");
        if (helpOnFocus != null) {
            String helpParam[] = new String[] {
                    EncodeUtils.encodeString(helpOnFocus).toString() };
            insertCall(attrMap, "onfocus", "showHelpOnFocus", helpParam);
            insertCall(attrMap, "onblur", "clearHelpOnBlur", null);
        }
    }
    
    protected String getAttribute(Map<String, Object> attrMap, String attrName) {
        Object attrValue = attrMap.get(attrName);
        if (attrValue != null)
            return attrValue.toString();
        else
            return null;
    }
    
    protected void insertCall(Map<String, Object> attrMap, String attrName,
            String functionName, String functionParams[]) {
        String attrValue = getAttribute(attrMap, attrName);
        if (attrValue != null && attrValue.indexOf(functionName) != -1)
            return;
        StringBuilder buf = EncodeUtils.encodeCall(
                functionName, functionParams);
        if (attrValue != null && attrValue.length() > 0) {
            buf.append(';');
            buf.append(attrValue);
        }
        attrMap.put(attrName, buf.toString());
    }
    
    public String getFamily() {
        return "HelpOnFocus";
    }

}

The HelpOnFocus.js file (shown in Listing 16) contains the showHelpOnFocus() and clearHelpOnBlur() functions, whose invocations are coded within the onfocus and onblur attributes. The setInnerHTML() function inserts the given content within the HTML element with the given id.


Listing 16. The HelpOnFocus.js file
function setInnerHTML(id, content) {
    document.getElementById(id).innerHTML = content;
}
    
function showHelpOnFocus(msg) {
    setInnerHTML("helpOnFocus", msg);
}

function clearHelpOnBlur() {
    setInnerHTML("helpOnFocus", "");
}

Like any custom JSF component, HelpOnFocusComponent must be configured in faces-config.xml (see Listing 17).


Listing 17. Configuring HelpOnFocusComponent in faces-config.xml
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" ... version="1.2">
    ...
    <component>
        <component-type>HelpOnFocusComponent</component-type>
        <component-class>jsfcssjs.HelpOnFocusComponent</component-class>
        <component-extension>
            <component-family>HelpOnFocus</component-family>
        </component-extension>
    </component>

</faces-config>

Listing 18 shows the HelpOnFocusTag class, which implements the tag handler for the custom component. The UIComponentELTag base class is part of the JSF 1.2 API. If you want to use the custom component in a JSF 1.1-based application, the superclass of the tag handler must be UIComponentTag.


Listing 18. The HelpOnFocusTag class
package jsfcssjs;

import javax.faces.webapp.UIComponentELTag;

public class HelpOnFocusTag extends UIComponentELTag {

    public String getComponentType() {
        return "HelpOnFocusComponent";
    }

    public String getRendererType() {
        return null;
    }

}

The name and attributes of the custom tag are specified in the js.tld file (shown in Listing 19). The HelpOnFocusTag handler doesn't have any setter methods for its attributes because it inherits them from UIComponentELTag.


Listing 19. The js.tld file
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee" ... version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>js</short-name>
    <uri>/js.tld</uri>
    <tag>
        <name>helpOnFocus</name>
        <tag-class>jsfcssjs.HelpOnFocusTag</tag-class>
        <body-content>JSP</body-content>
        <attribute>
            <name>id</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>binding</name>
            <required>false</required>
            <deferred-value>
                <type>jsfcssjs.HelpOnFocusComponent</type>
            </deferred-value>
        </attribute>
        <attribute>
            <name>rendered</name>
            <required>false</required>
            <deferred-value>
                <type>boolean</type>
            </deferred-value>
        </attribute>
    </tag>
</taglib>

JavaScript encoding utilities

The HelpOnFocusComponent class presented above uses the helper methods provided by the EncodeUtils class. The encodeString() method (see Listing 20) escapes the backspace, TAB, CR, LF, and non-ASCII characters so the returned value can be used as a string literal in the JavaScript code. In addition, the ", &, <, and > characters are replaced with &quot;, &amp;, &lt;, and &gt; so the encoded string can be included within the HTML page. Two quote characters are used as delimiters. For example, if you pass abc \ " & < > [TAB] [LF] [CR] 123 to encodeString(), the returned value will be "abc \\ &quot; &amp; &lt; &gt; \t \n \r 123".


Listing 20. The encodeString() method of the EncodeUtils class
package jsfcssjs;

public class EncodeUtils {

    public static StringBuilder encodeString(String str) {
        if (str == null)
            return null;
        StringBuilder buf = new StringBuilder();
        buf.append('"');
        int n = str.length();
        for (int i = 0; i < n; i++) {
            char ch = str.charAt(i);
            switch (ch) {
                case '\\': buf.append("\\\\"); break;
                case '\'': buf.append("\\\'"); break;
                case '"':  buf.append("&quot;"); break;
                case '&':  buf.append("&amp;"); break;
                case '<':  buf.append("&lt;"); break;
                case '>':  buf.append("&gt;"); break;
                case '\t': buf.append("\\t"); break;
                case '\r': buf.append("\\r"); break;
                case '\n': buf.append("\\n"); break;
                default: {
                    if (' ' <= ch && ch <= '~')
                        buf.append(ch);
                    else {
                        buf.append("\\u");
                        for (int j = 3; j >= 0; j--) {
                            int h = (((int) ch) >> (j*4)) & 0x0f;
                            buf.append((char) (h<10 ? '0'+h : 'a'+h-10));
                        }
                    }
                }
            }
        }
        buf.append('"');
        return buf;
    }
    ...
}    

The encodeCall() method (see Listing 21) builds a function call using the given parameters.


Listing 21. The encodeCall() method of the EncodeUtils class
public class EncodeUtils {
    ...
    public static StringBuilder encodeCall(
            String functionName, String functionParams[]) {
        StringBuilder buf = new StringBuilder();
        buf.append(functionName);
        buf.append('(');
        if (functionParams != null)
            for (int i = 0; i < functionParams.length; i++) {
                if (i > 0)
                    buf.append(',');
                buf.append(functionParams[i]);
            }
        buf.append(')');
        return buf;
    }
    
}

For a better understanding of the encoding methods, consider the example from Listing 22, which contains an input component that already has an onfocus attribute. A helpOnFocus attribute is also added to this component with <f:attribute> and the whole form is wrapped by a <js:helpOnFocus> component.


Listing 22. String encoding example
<% request.setAttribute("msg", "abc \\ \" & < > \t \n \r 123"); %>
...
<js:helpOnFocus>
    <h:form>
        <h:inputText ... onfocus="alert('focus')">
            <f:attribute name="helpOnFocus" value="#{msg}"/>
        </h:inputText>
    </h:form>
</js:helpOnFocus>
...
<div id="helpOnFocus">
</div>
...

When the page is executed, the <js:helpOnFocus> component traverses the nested component tree and sets the onfocus and onblur attributes to display and clear the help message. Listing 23 shows the HTML that is rendered by the JSF components. The onfocus attribute contains the showHelpOnFocus() call along with the alert('focus') expression from the example shown in Listing 22. The & characters and the " delimiters of the encoded string are escaped one more time by the <h:inputText> component, which encodes the values of its own attributes.


Listing 23. Encoded string
<form ...>
...
<input ... onblur="clearHelpOnBlur()" 
           onfocus="showHelpOnFocus(&quot;abc \\ &amp;quot; &amp;amp; 
&amp;lt; &amp;gt; \t \n \r 123&quot;);alert('focus')" />
...
</form>
...
<div id="helpOnFocus">
</div>
...

When the Web browser parses and decodes the piece of HTML from Listing 23, the value retrieved from the onfocus attribute is showHelpOnFocus("abc \\ &quot; &amp; &lt; &gt; \t \n \r 123");alert('focus'). The browser passes this code to its JavaScript engine, which calls the showHelpOnFocus() function that inserts abc \ &quot; &amp; &lt; &gt; [TAB] [NL] [CR] 123 within the <div id="helpOnFocus"> element of the Web page, and the browser shows abc \ " & < > 123.

The developerWorks Ajax resource center
Check out the Ajax resource center, your one-stop shop for free tools, code, and information on developing Ajax applications. The active Ajax community forum, hosted by Ajax expert Jack Herrington, will connect you with peers who might just have the answers you're looking for right now.

Using the custom component in a JSF page

The HelpOnFocus.jsp page (see Listing 24) is another example that uses the <js:helpOnFocus> component. The JSF form contains three input components: a text field, a checkbox, and a drop-down list. All these components use the <f:attribute> tag to specify help messages.


Listing 24. The HelpOnFocus.jsp example
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<%@ taglib prefix="js" uri="/js.tld" %>

<f:view>
    ...
    <script type="text/javascript"
        src="<%=request.getContextPath()%>/HelpOnFocus.js">
    </script>
    ...
    <js:helpOnFocus>
        ...
        <h:inputText id="text" ...>
            <f:attribute name="helpOnFocus"
                    value="Enter the text you want to search for."/>
        </h:inputText>
        ...
        <h:selectBooleanCheckbox id="matchCase" ...>
            <f:attribute name="helpOnFocus"
                    value="Distinguish between lowercase and uppercase
                                                        characters."/>
        </h:selectBooleanCheckbox>
        ...
        <h:selectOneMenu id="language" ...>
            ...
            <f:attribute name="helpOnFocus"
                    value="Select the language of the searched text."/>
        </h:selectOneMenu>
        ...
        <f:verbatim>
            <div id="helpOnFocus">
            </div>
        </f:verbatim>
        ...
    </js:helpOnFocus>
    ...
</f:view>

Listing 25 shows the HTML produced by the HelpOnFocus.jsp page.


Listing 25. HTML generated by HelpOnFocus.jsp
...
<script type="text/javascript" 
    src="/jsf12js/HelpOnFocus.js">
</script>
...
<input id="searchForm:text" type="text" ... onblur="clearHelpOnBlur()" 
    onfocus="showHelpOnFocus(&quot;Enter the text you want to search for.&quot;)"/>
...
<input id="searchForm:matchCase" type="checkbox" ... onblur="clearHelpOnBlur()" 
    onfocus="showHelpOnFocus(&quot;Distinguish between lowercase and uppercase
        \r\n                                                 characters.&quot;)" />
...
<select id="searchForm:language" ... onblur="clearHelpOnBlur()" 
    onfocus="showHelpOnFocus(&quot;Select the language of the searched text.&quot;)">
    ...
</select>
...
<div id="helpOnFocus">
</div>
...

Conclusion

This article showed you how to develop JavaScript event handlers that update the HTML rendered by JSF components. It introduced several Web techniques, including:

  • Setting the className property to change the value of the class attribute
  • Using the innerHTML property to insert some content within a HTML element
  • Hiding and displaying JSF components with CSS
  • Implementing client-side validation with JavaScript

It also showed you how to use custom attributes in conjunction with a wrapper component for adding new features to existing JSF components.



Download

DescriptionNameSizeDownload method
Sample application for this articlejsfcssjs_p2.zip30KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Andrei Cioroianu is the founder of Devsphere, a provider of Java EE development and Ajax/JSF consulting services. He's been using Java and Web technologies since 1997 and has 10 years of professional experience in solving complex technical problems and managing the full life cycle of commercial products, custom applications, and open source frameworks. You can reach Andrei through the contact form at devsphere.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Java technology
ArticleID=288485
ArticleTitle=Craft Ajax applications using JSF with CSS and JavaScript, Part 2: Dynamic JSF forms
publish-date=02122008
author1-email=andcio@gmail.com
author1-email-cc=