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
4
votes
1 answer

JSF composite:attribute with f:attribute conversion error

I'm implementing a JSF component and need to conditionally add some attributes. This question is similar to a previous JSF: p:dataTable with f:attribute results in "argument type mismatch" error, but with a completely different error message, so I…
Thor
  • 6,607
  • 13
  • 62
  • 96
4
votes
1 answer

How to render a composite component using a custom renderer?

I would like to know how to render a composite component, through Java, I mean I have:
Angel
  • 155
  • 1
  • 1
  • 14
4
votes
1 answer

Inheriting component attributes in a composite component which extends an existing JSF component

I wish to extend the following element: to include code to produce a depressed button:
Mark W
  • 5,824
  • 15
  • 59
  • 97
4
votes
1 answer

Eclipse + JSF + Facelets + composite component = CANNOT_FIND_FACELET_TAGLIB

I'm trying to add a composite component to my JSF Facelets application. The composite component (email.xhtml) is as follows:
Alex Averbuch
  • 3,245
  • 5
  • 33
  • 44
3
votes
1 answer

How to set the focus to the last item in ui:repeat JSF

I have a scrollable div and I like to set the focus at the last element. How can I achieve this?
MC Toni
  • 31
  • 2
3
votes
1 answer

How to parameterize requiredMessage attribute in composite component?

BalusC provided a good answer to a question about how to set messages per composite component. Specifying different error messages for different composite components The answer involved using per component resource bundles. Ive applied this approach…
Andrew Bucknell
  • 1,880
  • 3
  • 21
  • 32
3
votes
1 answer

How to extract first component ID from #{cc.clientId}?

I neet to get a specific parent component ID in a composite component. I've only found out how to get the entire chain of IDs, namely as I wrote in the title: #{cc.clientId}. It delivers (I don't know how they're called) Id1:Id2:Id3, but I need only…
3
votes
1 answer

Performance of JSF Composite components

Since a few weeks we have performance problems in our web applications. First we thought the problems belongs to large DOM. Large DOM isn´t really good but thats not the main perfomance problem. The problem are the composite components. The last…
user652158
3
votes
1 answer

Packaging composite component in JSF2 with Netbeans 7.0.1, Maven

I've read a lot of things on the Internet about packaging JSF2 composite component in a JAR file. Does somebody know where I can find what MUST be the structure of JAR (specs, official doc, etc, ). Is there a way to do it with Netbeans IDE, or does…
simplicity4k
  • 31
  • 1
  • 4
3
votes
1 answer

Using one component (dataTable) id inside composite component

How can I use id of DataTable Component (Primefaces 2.2.1) inside Composite Component in Java Server Faces 2.1 ? Now, I have a view:
vizzdoom
  • 736
  • 1
  • 9
  • 19
3
votes
1 answer

Can't access javascript file in jsf component

I have a jsf component that must access to a javascript file, i added this whith outputScript as in the code bellow, I get an error in the generated html, and the javascript can't be reached. The javascript file is located in document_root/js…
Aziz Mehdaoui
  • 257
  • 1
  • 7
  • 16
3
votes
0 answers

Call JSF action method from custom component with parameters and table

I'm trying to make a composite component containing a table with a commandButton on each row, calling an actionmethod taking the row object as a parameter. It would look like this without being a custom component:
Rasmus Franke
  • 4,434
  • 8
  • 45
  • 62
3
votes
1 answer

setPropertyActionListener on commandLink inside ui:repeat with a composite component

I've created a composite component that has a commandLink embedded inside of a ui:repeat. I need to be able to dynamically change the method that is called via the commandLink's action property but it doesn't seem to be possible due to the fact…
jjross
  • 678
  • 1
  • 6
  • 19
3
votes
2 answers

Problem with evaluating El expressionin combination with seam 3 and JSF2 composite component valueChangeListener

i have following construct: @Named public class SpecificAction extends BasicAction { public void calulateSomething(ValueChangeEvent event) {...} } } @Named public abstract class BasicAction { public void…
3
votes
1 answer

Extended @FacesComponent as composite interface componentType renders nothing

I'm trying to extend JSF's component class (let it be one of h:panelGroup) and render it via composite component: Step 1: @FacesComponent(value="customPanel") public class CustomPanel extends HtmlPanelGroup { // or UIPanel } Step 2: