Questions tagged [composite-component]

"Composite Component" is a JSF 2.x / Facelets specific term for reuseable UI components which are declared using pure XML rather than Java. The composite component XML declaration tags are available under the namespace `http://xmlns.jcp.org/jsf/composite`.

“Composite Component” is a JSF 2.x / Facelets specific term for reuseable UI components which are declared using pure XML rather than Java. The composite component XML declaration tags are available under the namespace http://xmlns.jcp.org/jsf/composite. Before JSF 2.2, the namespace http://java.sun.com/jsf/composite should be used instead.

Creating composite components

Prepare directory structure

First create a directory resources in the public webcontent (there where the WEB-INF directory and all regular Facelets files also are).

WebContent
 |-- WEB-INF
 |    `-- lib
 |-- resources   <---
 `-- test.xhtml

JSF 2.2 and later allows to change the resources directory by specifying a parameter named javax.faces.WEBAPP_RESOURCES_DIRECTORY in the file. It may be reasonable to change the directory to, for example, /WEB-INF/resources, since files under /WEB-INF are not readable via HTTP.

In the resources directory, create a directory exclusively for composite components. The directory name ends up as the extra path in the composite component namespace URI. You're free to choose the name. We'll take mycomponents as an example.

WebContent
 |-- WEB-INF
 |    `-- lib
 |-- resources
 |    `-- mycomponents   <---
 `-- test.xhtml

This way the composite components in this directory are available in all templates by the following namespace:

<html xmlns:my="http://xmlns.jcp.org/jsf/composite/mycomponents">

The prefix my is free to your choice. The http://xmlns.jcp.org/jsf/composite/ part is mandatory. The mycomponents part should be just the same as the directory name.

As a Hello World composite component example, we'll create composite component which shows a simple rating score with stars. We need to create a new XHTML file. The filename becomes the composite component tag name. You're free to choose the name. Let's call it rating.xhtml.

WebContent
 |-- WEB-INF
 |    `-- lib
 |-- resources
 |    `-- mycomponents
 |         `-- rating.xhtml   <---
 `-- test.xhtml

This way the composite component is available in all templates as follows:

<my:rating />

Create composite component

Here's how a basic composite component template look like. Put this in rating.xhtml.

<ui:component
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:cc="http://xmlns.jcp.org/jsf/composite"
>
    <cc:interface>
        <!-- Define component attributes here -->
    </cc:interface>
    <cc:implementation>
        <!-- Define component body here -->
    </cc:implementation>
</ui:component>

We'd like to define the following attributes:

  • score, integer, required. The star score.
  • maxScore, integer, optional, default 100. The maximum possible score.
  • totalStars, integer, optional, default 10. The total amount of stars to display.

Now, here's how the final implementation look like. Note that the attributes are available by #{cc.attrs.attributename}.

<ui:component 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:cc="http://xmlns.jcp.org/jsf/composite"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
    xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"
>
    <cc:interface>
        <cc:attribute name="score" type="java.lang.Integer" required="true" />
        <cc:attribute name="maxScore" type="java.lang.Integer" default="100" />
        <cc:attribute name="totalStars" type="java.lang.Integer" default="10" />
    </cc:interface>
    <cc:implementation>
        <c:set var="filled" value="#{fn:substringBefore(cc.attrs.score / (cc.attrs.maxScore / cc.attrs.totalStars), '.')}" />
        <span style="font-size: 1.5em;">
            <c:forEach begin="1" end="#{cc.attrs.totalStars}" varStatus="loop">
                <h:outputText value="&#9733;" rendered="#{loop.index le filled}" />            
                <h:outputText value="&#9734;" rendered="#{loop.index gt filled}" />            
            </c:forEach>
        </span> 
    </cc:implementation>
</ui:component>

Here's how you can use it in test.xhtml:

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html" 
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:my="http://xmlns.jcp.org/jsf/composite/mycomponents"
>
    <h:head>
        <title>Rating composite component demo</title>
    </h:head>
    <h:body>
        <my:rating score="60" /><br />
        <my:rating score="5" maxScore="10" /><br />
        <my:rating score="80" totalStars="5" /><br />
    </h:body>
</html>

Here's how the result should look like (only if your browser supports the Unicode star fonts; you're free to replace them by real images or even introduce a half star, which unfortunately isn't available in Unicode):

★★★★★★☆☆☆☆

★★★★★☆☆☆☆☆

★★★★☆

Create backing component

The above implementation has one disadvantage due to use the use of JSTL <c:forEach> : as JSTL runs during view build time instead of view render time, the above implementation cannot be used inside a repeating component such as <h:dataTable> or <ui:repeat>. We would like to use an <ui:repeat> instead, but it doesn't support begin and end attributes. So we'd like to attach some Java code so that it converts the totalStars to a blank object array of exactly that size so that it can be used in the value attribute. Ideally, this would be done using an EL function, but for learning/wiki purposes we'll use a so-called "backing component" instead.

To create such a backing component, we need to create a class which extends UINamingContainer or at least implements NamingContainer and returns UINamingContainer.COMPONENT_FAMILY in the getFamily() method. Here's a basic template:

package com.example;

import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;

@FacesComponent("myCompositeComponent")
public class MyCompositeComponent extends UINamingContainer {

    // ...

}

Note the value of the @FacesComponent attribute. It's the one which you should specify in the componentType attribute of the <cc:interface> tag:

<cc:interface componentType="myCompositeComponent">

This way an instance of the backing component will be used behind the #{cc} variable instead. This offers you the possibility to define getter and action methods like value="#{cc.items}", action="#{cc.doSomething}" and so on. All of the <cc:attribute> attribues are available in the backing component by the inherited UIComponent#getAttributes() method which provides easy access to the attributes.

For our rating composite component, the backing component implementation should look like this:

package com.example;

import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;

@FacesComponent("ratingComponent")
public class RatingComponent extends UINamingContainer {

    public Object[] getItems() {
        Object totalStars = getAttributes().get("totalStars");
        int size = Integer.valueOf(String.valueOf(totalStars));
        return new Object[size];
    }

}

And here's how the rating.xhtml should now look like:

<ui:component 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:cc="http://xmlns.jcp.org/jsf/composite"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
    xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions"
>
    <cc:interface componentType="ratingComponent">
        <cc:attribute name="score" type="java.lang.Integer" required="true" />
        <cc:attribute name="maxScore" type="java.lang.Integer" default="100" />
        <cc:attribute name="totalStars" type="java.lang.Integer" default="10" />
    </cc:interface>
    <cc:implementation>
        <c:set var="filled" value="#{fn:substringBefore(cc.attrs.score / (cc.attrs.maxScore / cc.attrs.totalStars), '.')}" />
        <span style="font-size: 1.5em;">
            <ui:repeat value="#{cc.items}" varStatus="loop">
                <h:outputText value="&#9733;" rendered="#{loop.index lt filled}" />            
                <h:outputText value="&#9734;" rendered="#{loop.index ge filled}" />            
            </ui:repeat>
        </span>
    </cc:implementation>
</ui:component>

Note the value="#{cc.items}" in the above example. It basically calls getItems() method on the instance of the backing component. Also note that we got rid of JSTL <c:forEach>, so the above will work properly inside a repeating JSF component such as <ui:repeat>, <h:dataTable> and so on.

<h:dataTable value="#{bean.products}" var="product">
    <h:column>#{product.name}</h:column>
    <h:column><my:rating score="#{product.rating}" /></h:column>
</h:dataTable>

Online resources:

Related tag info pages:

775 questions
8
votes
1 answer

Validator for input field inside composite component is never fired

I've created some Facelets to make developing our pages easier. Particularly, I've created a series of Facelets for input components. I have 1 Facelet, that displays a label around the input field. Beyond that, I have Facelets like…
Shadowman
  • 11,150
  • 19
  • 100
  • 198
8
votes
1 answer

Can I determine if a JSF2 facet is defined in a composite component?

I am creating a JSF2 Facelets composite component. I would like the HTML to render differently if a particular facet is defined. Is there any way to check if a has been defined for a composite component?
Shadowman
  • 11,150
  • 19
  • 100
  • 198
7
votes
1 answer

Why does composite component "rendered" attribute throw an IllegalArgument Exception?

I create a composite component like this:
AlanObject
  • 9,613
  • 19
  • 86
  • 142
7
votes
1 answer

Adding action methods to a composite component

I am learning about composite components with JSF 2.0 and i want my component to be able to trigger methods from backing beans, so i created a simple example, but something is wrong. This is the component i created:
javing
  • 12,307
  • 35
  • 138
  • 211
7
votes
1 answer

Include a javascript for composite component only once in a page despite of composite components themselves used multiple times

How do I include a JavaScript code only once for multiple usages of a composite component on a page? Initially I had put I put the JS code inside the cc:implementation tags but that lead to the script being included each time with the components.…
Rajat Gupta
  • 25,853
  • 63
  • 179
  • 294
7
votes
3 answers

Injecting Resources Into UIComponent (aka does CDI work here?)

I am writing a (composite) component that needs to interact with my DAO. Here is how the Java part is declared: @FacesComponent(value="selectLocation") public class SelectLocation extends UINamingContainer { To get the DAO object, I tried the CDI…
AlanObject
  • 9,613
  • 19
  • 86
  • 142
7
votes
1 answer

How to refactor snippet of old JSP to some JSF equivalent?

ORIGINAL JSP (WorkItem.jsp) <%@ include file="inc_done_button.jsp" %>
jeff
  • 3,618
  • 9
  • 48
  • 101
7
votes
1 answer

What is the difference between composite:insertFacet and composite:renderFacet?

I am using GlassFish 3.1.2 and trying to use composite:insertFacet in a composite component, but the HTML Markup is not generated when using my CC. The same code works fine when I use composite:renderFacet, but I want to understand why…
Tarik
  • 4,961
  • 3
  • 36
  • 67
7
votes
2 answers

Properties of new tags using composite component are not displayed by Eclipse auto complete shortcurt

I have developed composite components using JSF 2.0 in Eclipse. I've been putting my XHTML tag files inside resources folder. When I hit ctrl + space in keyboard, the property of the tag are not displayed. I found some tips told to install "Jboss…
7
votes
2 answers

JSF 2.1.13 custom component not found: Tag Library supports namespace: but no tag was defined for name:

Problem I am using JSF 2.1.13 to create a prototype to demostrate the benefits of JSF over our current webapp built with JSP and struts 1.1. I following code using works with JSF 2.2.6, but I had to down grade once I found out that Oracle Weblogic…
pgreen2
  • 3,601
  • 3
  • 32
  • 59
7
votes
3 answers

Issue with JSF ui:composition and composite component

I'm trying to find out if this is a JSF/EL issue or something wrong here. Basically, I wanted to pass an item object as a ui:param to a ui:composition and have a button inside (i.e. bootstrap buttons so they're actually html links hence the use of…
Jordan
  • 370
  • 3
  • 13
7
votes
1 answer

Proper using of Facelet templates & Composite Components

I'm still not sure about proper using of JSF Templates & Composite Components. I need create an enterprise web applications, which will have a lot of pages. Every page will have the same header, menu, footer and of course different content (= JSF…
sasynkamil
  • 859
  • 2
  • 12
  • 23
6
votes
1 answer

Empty id attribute is not allowed in JSF Composite component

I am facing an issue "Empty id attribute is not allowed in JSF" while using the below mentioned composite component for a group of buttons (button's count can be 1 to 3) (I use Mojarra 2-0-8 on Tomcat-7) .
jvG
  • 403
  • 4
  • 6
  • 14
6
votes
1 answer

How to save state when extending UIComponentBase

I'm creating a composite component that will wrap a datatable to implement very simple paging. I need to save state (the current page number) between ajax requests. I tried creating fields in my FacesComponent, but I discovered they are wiped out…
Jonathan S. Fisher
  • 8,189
  • 6
  • 46
  • 84
6
votes
1 answer

Accessing JSF2 composite component attributes in backing component

I'm developing a JSF2/Primefaces app and I'm having trouble with accessing attributes defined in an interface of a composite component in this component's backing bean. My component is defined as follows:
1 2
3
51 52