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

Make attributes of Composite Component from JAR available in autocomplete

I've made a Composite Component and archived it in a *.jar file. My solution is based on this tutorial : How to package JSF2 composite component as distributable JAR and this question: Java EE6> Packaging JSF facelets (xhtml) and ManagedBeans as…
Anatoly
  • 5,056
  • 9
  • 62
  • 136
4
votes
0 answers

How to avoid sharing of values stored in StateHelper of composite components placed inside PrimeFaces datatable?

My composite components share values stored in StateHelper when placed inside PrimeFaces DataTable. The most of examples about keeping component state that I've seen suggest to use getStateHelper().put()/eval() methods of UINamingContainer. I do use…
toxich
  • 41
  • 5
4
votes
1 answer

JSF Combine ui:param with composite component

you have saved me many times ago with this forum, but now I am really stuck and don't now where to search any longer... I always get the following error message (warning level, but method is also not executed…
4
votes
2 answers

Composite component folder structure

JSF spec 2.2 (2013-03-20) says in item 10.3.3.1 (Declaring a composite component library for use in a Facelet page): If a facelet taglibrary is declared in an XHTML page with a namespace starting with the string …
Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65
4
votes
0 answers

Keeping @ViewScoped property states in composite component backings

This question is related with my previous one about initializing composite components. Providing I've got a homegrown composite component and a @ViewScoped managed bean, I want certain properties of the managed bean to be reflected in the component.…
Aritz
  • 30,971
  • 16
  • 136
  • 217
4
votes
1 answer

Getting correct parent ID in composite components

For partial updating my composite components, I have some problems finding the correct parent IDs. e.g. if my component is inside of a tabView
stg
  • 2,757
  • 2
  • 28
  • 55
4
votes
1 answer

Validation/conversion for two component based composite in JSF

I'm developing a JSF web application where I need to use periodicities as data structure. Here there are the Java classes I work with: public class Periodicity implements Serializable { private Integer value = 0; private PeriodicityType…
Aritz
  • 30,971
  • 16
  • 136
  • 217
4
votes
0 answers

Redirect to same webflow view state causes exception with nested composites

Consider a simple page with an input text and some validation to it. The page is included in a Spring webflow as a view state. On validation fail the same view state needs to be redisplayed, including validation messages. This works fine. Using a…
Louise
  • 1,451
  • 1
  • 18
  • 40
4
votes
1 answer

Composite component required="true" not respected

In the composite:interface I have defined an attribute like this: Now when I use my composite component like this, without defining any attributes: I would expect an error to…
pgsandstrom
  • 14,361
  • 13
  • 70
  • 104
4
votes
1 answer

JSF2 difference between composite and cc

I was trying to create a composite component based on BalusC's excellent article. I couldn't get the attributes or any value from the backing component. Code:
miro
  • 149
  • 3
  • 11
4
votes
2 answers

Backing bean in composite component is recreated on every request

I have two variables "userId" and "name". When I click for example the "SHOW USERID" button it works fine and sets "renderUserId=true" and it shows it with the "render", but then if I click the other "SHOW" button, the Bean is reconstruct and I…
davidml
  • 153
  • 5
  • 20
4
votes
1 answer

How to prevent multiple composite components reset themselves on a JSF page?

I put this problem in a simple example, a composite component that calculates the sum of 2 inputs and prints the result in an outputText Main JSF page:
Alexandru Pupsa
  • 1,798
  • 4
  • 21
  • 40
4
votes
1 answer

How to get rid of the auto generated j_idt ID in composite component

I'm using below composite component:
MyFist
  • 413
  • 7
  • 19
4
votes
1 answer

FacesConverter forClass doesn't work with Composite Component

I've got a simple composite component which has to render a inputText. When a put the value and press commandButton the follow exception is throw: java.lang.IllegalArgumentException: Cannot convert 1 of type class java.lang.String to class…
4
votes
1 answer

JSF, Composite Component: method call with default attribute value as parameter

I am new to JSF and still learning. I tried searching for a solution to my specific problem described below but I could not find anything. If it because I was searching for the wrong things, please point me in the right direction, but hopefully it…
rdcrng
  • 3,415
  • 2
  • 18
  • 36