Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Creating a JSF composite component

Save for later
  • 9 min read
  • 22 Oct 2014

article-image

This article by David Salter, author of the book, NetBeans IDE 8 Cookbook, explains how to create a JSF composite component in NetBeans.

(For more resources related to this topic, see here.)

JSF is a rich component-based framework, which provides many components that developers can use to enrich their applications.

JSF 2 also allows composite components to be easily created, which can then be inserted into other JSF pages in a similar way to any other JSF components such as buttons and labels.

In this article, we'll see how to create a custom component that displays an input label and asks for corresponding input. If the input is not validated by the JSF runtime, we'll show an error message. The component is going to look like this:

creating-jsf-composite-component-img-0

The custom component is built up from three different standard JSF components. On the left, we have a <h:outputText/> component that displays the label. Next, we have a <h:inputText /> component. Finally, we have a <h:message /> component. Putting these three components together like this is a very useful pattern when designing input forms within JSF.

Getting ready

To create a JSF composite component, you will need to have a working installation of WildFly that has been configured within NetBeans.

We will be using the Enterprise download bundle of NetBeans as this includes all of the tools we need without having to download any additional plugins.

How to do it…

First of all, we need to create a web application and then create a JSF composite component within it. Perform the following steps:

  1. Click on File and then New Project….
  2. Select Java Web from the list of Categories and Web Application form the list of Projects.
  3. Click on Next.
  4. Enter the Project Name value as CompositeComp.
  5. Click on Next.
  6. Ensure that Add to Enterprise Application is set to <None>, Server is set to WildFly Application Server, Java EE Version is set to Java EE 7 Web, and Context Path is set to /CompositeComp.
  7. Click on Next.
  8. Click on the checkbox next to JavaServer Faces as we are using this framework.
  9. All of the default JSF configurations are correct, so click on the Finish button to create the project.
  10. Right-click on the CompositeComp project within the Projects explorer and click on New and then Other….
  11. In the New File dialog, select JavaServer Faces from the list of Categories and JSF Composite Component from the list of File Types.
  12. Click on Next.
  13. On the New JSF Composite Component dialog, enter the File Name value as inputWithLabel and change the folder to resourcescookbook.creating-jsf-composite-component-img-1
  14. Click on Finish to create the custom component.

In JSF, custom components are created as Facelets files that are stored within the resources folder of the web application. Within the resources folder, multiple subfolders can exist, each representing a namespace of a custom component. Within each namespace folder, individual custom components are stored with filenames that match the composite component names.

creating-jsf-composite-component-img-2

We have just created a composite component within the cookbook namespace called inputWithLabel.

Within each composite component file, there are two sections: an interface and an implementation. The interface lists all of the attributes that are required by the composite component and the implementation provides the XHTML code to represent the component.

Let's now define our component by specifying the interface and the implementation. Perform the following steps:

  1. The inputWithLabel.xhtml file should be open for editing. If not, double–click on it within the Projects explorer to open it.
  2. For our composite component, we need two attributes to be passed into the component. We need the text for the label and the expression language to bind the input box to. Change the interface section of the file to read:
       <cc:attribute name="labelValue" />
       <cc:attribute name="editValue" />
    </cc:interface>

  3. To render the component, we need to instantiate a <h:outputText /> tag to display the label, a <h:inputText /> tag to receive the input from the user, and a <h:message /> tag to display any errors that are entered for the input field. Change the implementation section of the file to read:
    <cc:implementation>
       <style>
       .outputText{width: 100px; }
       .inputText{width: 100px; }
       .errorText{width: 200px; color: red; }
       </style>
       <h:panelGrid id="panel" columns="3" columnClasses="outputText, inputText, errorText">
           <h:outputText value="#{cc.attrs.labelValue}" />
           <h:inputText value="#{cc.attrs.editValue}" id="inputText" />
           <h:message for="inputText" />
       </h:panelGrid>
    </cc:implementation>

  4. Click on the lightbulb on the left-hand side of the editor window and accept the fix to add the h=http://><html
      
       >
  5. We can now reference the composite component from within the Facelets page. Add the following code inside the <h:body> code on the page:
    <h:form id="inputForm">
       <cookbook:inputWithLabel labelValue="Forename" editValue="#{personController.person.foreName}"/>
       <cookbook:inputWithLabel labelValue="Last Name" editValue="#{personController.person.lastName}"/>
       <h:commandButton type="submit" value="Submit" action="#{personController.submit}"/>
    </h:form>

This code instantiates two instances of our inputWithLabel composite control and binds them to personController. We haven't got one of those yet, so let's create one and a class to represent a person. Perform the following steps:

  1. Create a new Java class within the project. Enter Class Name as Person and Package as com.davidsalter.cookbook.compositecomp.
  2. Unlock access to the largest independent learning library in Tech for FREE!
    Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
    Renews at AU $19.99/month. Cancel anytime
  3. Click on Finish.
  4. Add members to the class to represent foreName and lastName:
    private String foreName;
    private String lastName;

  5. Use the Encapsulate Fields refactoring to generate getters and setters for these members.
  6. To allow error messages to be displayed if the foreName and lastName values are inputted incorrectly, we will add some Bean Validation annotations to the attributes of the class. Annotate the foreName member of the class as follows:
    @NotNull
    @Size(min=1, max=25)
    private String foreName;

  7. Annotate the lastName member of the class as follows:
    @NotNull
    @Size(min=1, max=50)
    private String lastName;

  8. Use the Fix Imports tool to add the required imports for the Bean Validation annotations.
  9. Create a new Java class within the project. Enter Class Name as PersonController and Package as com.davidsalter.cookbook.compositecomp.
  10. Click on Finish.
  11. We need to make the PersonController class an @Named bean so that it can be referenced via expression language from within JSF pages.
  12. Annotate the PersonController class as follows:
    @Named
    @RequestScoped
    public class PersonController {

  13. We need to add a Person instance into PersonController that will be used to transfer data from the JSF page to the named bean. We will also need to add a method onto the bean that will redirect JSF to an output page after the names have been entered.
  14. Add the following to the PersonController class:
    private Person person = new Person();

    public Person getPerson() {
       return person;
    }

    public void setPerson(Person person) {
       this.person = person;
    }

    public String submit() {
       return "results.xhtml";
    }

  15. The final task before completing our application is to add a results page so we can see what input the user entered. This output page will simply display the values of foreName and lastName that have been entered.
  16. Create a new JSF page called results that uses the Facelets syntax.
  17. Change the <h:body> tag of this page to read:
    <h:body>
       You Entered:
       <h:outputText value="#{personController.person.foreName}" />&nbsp;
       <h:outputText value="#{personController.person.lastName}" />
    </h:body>

The application is now complete. Deploy and run the application by right-clicking on the project within the Projects explorer and selecting Run.

Note that two instances of the composite component have been created and displayed within the browser.

Click on the Submit button without entering any information and note how the error messages are displayed:

creating-jsf-composite-component-img-3

Enter some valid information and click on Submit, and note how the information entered is echoed back on a second page.

How it works…

Creating composite components was a new feature added to JSF 2. Creating JSF components was a very tedious job in JSF 1.x, and the designers of JSF 2 thought that the majority of custom components created in JSF could probably be built by adding different existing components together. As it is seen, we've added together three different existing JSF components and made a very useful composite component.

It's useful to distinguish between custom components and composite components. Custom components are entirely new components that did not exist before. They are created entirely in Java code and build into frameworks such as PrimeFaces and RichFaces. Composite components are built from existing components and their graphical view is designed in the .xhtml files.

There's more...

When creating composite components, it may be necessary to specify attributes. The default option is that the attributes are not mandatory when creating a custom component. They can, however, be made mandatory by adding the required="true" attribute to their definition, as follows:

<cc:attribute name="labelValue" required="true" />

If an attribute is specified as required, but is not present, a JSF error will be produced, as follows:

/index.xhtml @11,88 <cookbook:inputWithLabel> The following attribute(s) are required, but no values have been supplied for them: labelValue.

Sometimes, it can be useful to specify a default value for an attribute. This is achieved by adding the default="…" attribute to their definition:

<cc:attribute name="labelValue" default="Please enter a value" />

Summary

In this article, we have learned to create a JSF composite component using NetBeans.

Resources for Article:


Further resources on this subject: