Creating A Composite Component Tutorial
Creating A Composite Component Tutorial
Although Facelets and composite components were present in JSF 1.x, the release of JSF 2 has seen a strong focus on the Facelets view technology. As part of this focus composite components have been substantially improved with new features and bug fixes. This tutorial will deal with creating a custom composite component for use in our demo application. This tutorial assumes the reader has an understanding of JSF and ICEfaces and creating and working with projects related to those technologies. The goal of this tutorial is to create a basic ICEfaces 2 project and simplify it with the addition of a "fieldSet" composite component, which will wrap the common grouping of an outputlabel, inputText, and message tag. The example itself is rather simple and allows a user to input their name.
Here is the entire list of steps worked through during this tutorial: 1. 2. 3. 4. 5. 6. Make the compositeComponent Project Add ICEfaces Create main.xhtml Create NameBean.java Deploy the Application Create a Composite Component o Create Directory Structure o Create Component Page 7. Using a Composite Component o Add Namespace o Use fieldSet.xhtml 8. Add Middle Name o Add to Bean o Add to Page 9. Re-Deploy the Application
Eclipse IDE for Java EE Developers - Version Helios Tomcat 7.x Web Server Java 6.x ICEfaces 2
Using Eclipse create a new Dynamic Web Project called compositeComponent. o Target runtime: Apache Tomcat v7.0 o Dynamic web module version: 3.0 o Configuration: JavaServer Faces v2.0 Project (Mojarra)
2. Add ICEfaces
Add the icefaces.jar to your project from the ICEfaces 2 bundle. This can be added to the project through a custom User Library or by putting it into compositeComponent/WEBINF/lib/. The approach doesn't matter as long as the jar is included in the deployed war file.
3. Create main.xhtml
Create a new page called main.xhtml and paste the code below: main.xhtml
<!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:f="http://java.sun.com/jsf/core"> <h:head> <title>Composite Component - Main</title> </h:head> <h:body> <h:form> <h:panelGrid columns="3"> <f:facet name="header"> Hello, what is your name? </f:facet> <h:outputLabel for="firstName" value="First Name"/> <h:inputText id="firstName" value="#{nameBean.firstName}" required="true"/> <h:message for="firstName"/> <h:outputLabel for="lastName" value="Last Name"/> <h:inputText id="lastName" value="#{nameBean.lastName}" required="true"/> <h:message for="lastName"/> <f:facet name="footer"> <h:commandButton value="Submit"/><br/> </f:facet> </h:panelGrid> <h:outputText value="Greetings '#{nameBean.firstName} #{nameBean.lastName}'." rendered="#{nameBean.hasName}"/> </h:form> </h:body> </html>
This basic page prompts the user for their first and last name, and displays the result after the user has submitted the form. The page doesn't use any composite components, but the similar, repeated markup of h:outputLabel, h:inputText, and h:message is a perfect candidate for a composite component.
4. Create NameBean.java
Create a new Java class file called NameBean in the package org.icefaces.tutorial.composite.beans and paste the code below: NameBean.java
package org.icefaces.tutorial.composite.beans; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @ManagedBean(name="nameBean") @SessionScoped public class NameBean { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public boolean getHasName() { return firstName != null && lastName != null; } }
As with the page this backing bean is very simple. We manage the first and last name variables, and also have a convenience method to determine if a name has been entered or not.
When entering a name and pressing the "Submit" button you will see "Greetings, firstName lastName" appear at the bottom.
6b. Create Component Page Inside the example/ directory created above, create a new page called fieldSet.xhtml and paste the code below: fieldSet.xhtml
<?xml version="1.0" encoding="utf-8"?> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:composite="http://java.sun.com/jsf/composite"> <composite:interface> <composite:attribute name="label" /> <composite:attribute name="value" required="true" /> <composite:attribute name="required" default="false" /> <composite:editableValueHolder name="input" /> </composite:interface> <composite:implementation> <h:outputLabel for="input" value="#{cc.attrs.label}" style="float:left;"/> <h:inputText id="input" value="#{cc.attrs.value}" style="float:left;" required="#{cc.attrs.required}"/> <h:message for="input" id="msg"/> </composite:implementation> </html>
This is our composite component interface and implementation. The interface declares how the composite component will be used in a parent page, including available attributes and the
default values for those attributes. The implementation actually holds the markup that is inserted into the parent page when the composite component is used. The new markup used in our page as a result of creating the composite component: Example Usage
<ourComp:fieldSet label="Some Label Text" value="#{someBean.binding}"/>
In the <html> container at the top of main.xhtml add the namespace above. 7b. Use fieldSet.xhtml Now let's replace our first and last name markup with the new composite component. Replace the existing <h:panelGrid> with the following code: New panelGrid
<h:panelGrid> <f:facet name="header"> Hello, what is your name? </f:facet> <ourComp:fieldSet label="First Name" value="#{nameBean.firstName}" required="true"/> <ourComp:fieldSet label="Last Name" value="#{nameBean.lastName}" required="true"/> <f:facet name="footer"> <h:commandButton value="Submit"/><br/> </f:facet> </h:panelGrid>
The markup is simpler while still remaining functional. If we needed more attributes than the three (label, value, required) we made available in the composite component, we could just modify the composite:interface to add more "passthrough" attributes, such as maxlength, size, style, etc.
* Also modify the getHasName method to include the new middleName variable. 8b. Add to Page Add the new middleName by pasting another instance of our new composite component between the firstName and lastName markup in main.xhtml: Middle Name Markup
<ourComp:fieldSet label="Middle Name" value="#{nameBean.middleName}" required="true"/>
* Also modify the outputText at the bottom to include displaying the new #{nameBean.middleName} variable.