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
5
votes
0 answers

CompositeComponent Primefaces Dialog appendTo ="@(body)" not working

I'm using PF 5.1.5 and made some composite components with dialogs which all should be modal and appended to body (so the dialog is really modal). This works when I use dialogs in plain pages, but not if I use them in composite components. I think…
user3172567
  • 461
  • 1
  • 7
  • 19
5
votes
1 answer

not working via

I have a composite component which has ajax:
Mark W
  • 5,824
  • 15
  • 59
  • 97
5
votes
2 answers

Newbie in JSF: composition vs composite

I am starting development on a new web application which uses JSF 2 as the view technology. I have no prior experience with JSF and am a bit confused about the concepts. I read some documentation on JSF and the main idea was that it a component…
ats
  • 73
  • 1
  • 7
5
votes
2 answers

Managed Bean as Facelet parameter lets composite component prevent resolving

In the given case, I want to use a facelet with different ManagedBeans, so the regarding action-bean is given as an parameter:
L-Ray
  • 1,637
  • 1
  • 16
  • 29
5
votes
1 answer

evaluates always false

This is called 3 times, for each row once. (example table has 3 rows) ....
W vd L
  • 625
  • 9
  • 26
5
votes
1 answer

action and actionListener for p:commandButton in composite component

I am making composite component where i have commandButton. But it doesn't work. Usage: Code of component: commandButton.xhtml
WojciechKo
  • 1,511
  • 18
  • 35
5
votes
1 answer

Whats the difference between JSF Custom Composite Components vs Custom Classic Components

i want to build a custom JSF Component. Now i read some docs from oracle and saw a few code Examples. The problem is i am a bit confused: It seems there are two ways to build a custom component with JSF 2.0+. As far as i understood since JSF 2.0 i…
Nick Russler
  • 4,608
  • 6
  • 51
  • 88
5
votes
2 answers

Composite component listeners only working after page reload

I have a web page which is including a sub-page that changes according to the element I choose in the primefaces dock menu (ui:include). Some sub pages include a custom composite component I implemented. The first page the web app shows has all his…
fostiguy
  • 63
  • 6
5
votes
1 answer

How to access the parent Naming Container of Composite?

I have a JSP 2.0 , within that is a with a column that uses a Composite to render a special border about some content. Now I need to identify the in a ajax rendered attribute that is located in the…
Ralph
  • 118,862
  • 56
  • 287
  • 383
5
votes
1 answer

Components are with the same id inside ui:repeat

Unfortunately, primefaces accordionPanel doesn't works well in version 2.2.1 if you are trying to create tabs dynamically. This is my case, I need to create accordions if the user clicks an add icon, and remove if he clicks on x icon. No problem,…
brevleq
  • 2,081
  • 10
  • 53
  • 97
4
votes
2 answers

Nested composite component broken in JBoss 7.1.1

We use composite components inside other components in our project. Everything works just fine on JBoss 7.1.0, but on JBoss 7.1.1 we get errors like this: No handlers found for exception javax.faces.view.facelets.TagException:…
Xavier Portebois
  • 3,354
  • 6
  • 33
  • 53
4
votes
2 answers

Use of f:attribute inside a composite component

we have a (in our oppinion) very simple scenario here. But we got stuck somehow on composite components and f:attribute tags. I'll try to keep the code as simple as possible. Composite Component: ... …
SlimShady
  • 185
  • 3
  • 11
4
votes
1 answer

How to bundle several JSF2 composite component libraries under one namespace

We have a bunch of JSF 1.2 facelets components (ui:composition). They are organized in different folders like this... facelets /tags /inputfields /layout /core /... They are registered within a tag library descriptor…
Tim Brückner
  • 1,928
  • 2
  • 16
  • 27
4
votes
1 answer

How to evaluate MethodExpressions in JSF composite components

I am not sure about the "correct" way to deal with method expressions in composite components. My composite uses a backing class with action methods. Theses perform some default actions or delegate to an action method passed by the composite user as…
4
votes
1 answer

How to reference #{cc.clientId} in ajax update/process/render/execute?

I don't know how to reference descendant components of composite component in update or process (alias render or execute). I have this composite component resources/components/crud.xhtml:
Michele Mariotti
  • 7,372
  • 5
  • 41
  • 73