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

When to use , tag files, composite components and/or custom components?

I started using JSF 2.0 with Facelets recently and got puzzled by new composite components knowing existing and other templating techniques offered by Facelets 1.x. What is the difference between those approaches? Functionally they…
mrembisz
  • 12,722
  • 7
  • 36
  • 32
25
votes
2 answers

How to make a grid of JSF composite component?

I have lot's of outputLabel and inputText pairs in panelGrids
Anatoli
  • 303
  • 1
  • 5
  • 5
23
votes
2 answers

JSF 2 - How can I add an Ajax listener method to composite component interface?

I have a JSF 2 composite component that employs some Ajax behavior. I want to add a listener method to the tag inside my composite component, but the listener method should be provided as a in the…
Jim Tough
  • 14,843
  • 23
  • 75
  • 96
16
votes
1 answer

How to implement a dynamic list with a JSF 2.0 Composite Component?

I asked this question and although the answer directly satisfied my needs I am left with a feeling that there has to a simpler solution for this specific problem. I would like to have a composite component that accepts a list of items (The type of…
Ben
  • 10,020
  • 21
  • 94
  • 157
16
votes
1 answer

Pass method argument/parameter to composite-component action attribute

The title really says it all. I have made an attempt which failed with the error: Illegal attempt to pass arguments to a composite component lookup expression (i.e. cc.attrs.[identifier]). My attempt looks like this:
Ben
  • 10,020
  • 21
  • 94
  • 157
14
votes
2 answers

How to programmatically or dynamically create a composite component in JSF 2

I need to programmatically create composite components in JSF 2. After few days of searching and experiments I figured out this method (highly inspired by Lexi at java.net): /** * Method will attach composite component to provided component *…
Ondrej Bozek
  • 10,987
  • 7
  • 54
  • 70
14
votes
2 answers

Generate Documentation for JSF 2 composite components

I'm looking to generate documentation for a custom JSF 2 composite component library. The composite components are not referenced in any faces-config.xml file, but rather the .xhtml files for the composite components are stored in…
14
votes
1 answer

Weird behavior of JSF p:dataTable (first entry wrong in p:columns)

I have on a page two p:dataTable. The left one is mainly used for selection
Thor
  • 6,607
  • 13
  • 62
  • 96
13
votes
3 answers

How to check presence of optional attribute inside a composite component

I need to verify whether an optional attribute has been passed or not within my composite component. How can I achieve this?
MyFist
  • 413
  • 7
  • 19
12
votes
2 answers

Initialize a composite component based on the provided attributes

I'm writing my custom table composite component with Mojarra JSF. I'm also trying to bind that composite to a backing component. The aim is to be able to specify the number of elements the table has in a composite attribute, later on the bound…
Aritz
  • 30,971
  • 16
  • 136
  • 217
12
votes
2 answers

How to create a composite component for a datatable column?

Given this datatable (naturally working): HEADER If I define a custom component…
Federico
  • 561
  • 2
  • 11
  • 32
11
votes
1 answer

How to pass attributes to a composite-component

I am having trouble in using a JSF composite-component in the right way. I put some components together and everything was working. Then I just extracted the code to a composite-component, and passed the corresponding attributes and suddenly I am…
lostiniceland
  • 3,729
  • 6
  • 38
  • 50
11
votes
8 answers

PrimeFaces CommandButton Action not called inside Composite

In the code bellow the jsf html commandButton action is called perfectly. But primefaces commandButton action is not called.
Fernando Bonafé
  • 121
  • 1
  • 1
  • 6
11
votes
1 answer

How to attach ajax event to composite component?

I have the following composite component ()
Ronald
  • 113
  • 1
  • 1
  • 7
11
votes
1 answer

Nested JSF Composite Components leading to a Stack Overflow exception

The problem When I attempt to nest a Composite Component within itself, with some logic to end the infinite recursion I receive a stack overflow exception. My understanding is that tags run at view build time so I was not expecting to have…
Richard Tingle
  • 16,906
  • 5
  • 52
  • 77
1
2 3
51 52