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

How to reuse a lookup (popup) component for multiple inputs

here is what i am trying to achieve: I have a page that consists of a lot of (autocomplete) inputs that are used to select the same type of object (all in a different context). Every single input has to offer the ability to open a popup where the…
dag
  • 1,133
  • 12
  • 25
0
votes
1 answer

Implementing JSF Composite Component in Maven project

It seems people are able to implement composite components in SWF 2.3.1, but I cannot find a clear reference for how this is done. I have followed the basic structure for a JSF composite component, but my SWF application does not seem to recognize…
Rich
  • 2,805
  • 8
  • 42
  • 53
0
votes
1 answer

myfaces action method in composite component throws

I'm running into an odd issue with myfaces 2.1.10 (packaged with TomEE) involving composite components and action methods. Essentially, looking at the example below, myfaces seems to thing that the action method is a property instead and throws an…
Ali Cheaito
  • 3,746
  • 3
  • 25
  • 30
0
votes
2 answers

Target Unreachable error after adding validation

The error "/resources/components/hostForm.xhtml @25,84 value="#{cc.attrs.host.hostName}": Target Unreachable, 'host' returned null" occurs after I added to an inputText field in a custom tag. Without…
stacker
  • 68,052
  • 28
  • 140
  • 210
0
votes
0 answers

Autocomplete of composite component attributes in STS

I have created some composite components in my JSF project in STS 3.1.0. When I declare them in the view like this: xmlns:asw="http://java.sun.com/jsf/composite/asw-tags then everything works fine, but I don't have any code completion for…
0
votes
2 answers

Order of rendering when using composite components with WebFlow

When using Web Flow (2.3.1.RELEASE) in combination with JSF, I have a rendering problem when using a composite component of any kind and e.g. an component on 1 page after clicking a . The contents of the composite…
user1629683
0
votes
1 answer

Target Value on Composite Component Error on Updating entity

I am getting a strange error. I created a simple JSF composite component, that is:
Marco Noronha
  • 115
  • 1
  • 9
  • 31
0
votes
1 answer

Assigning a parameter in a JSF composite component

I'm trying to figure out if it's possible to pass values into a backing bean via a JSF composite component. So if I have an interface like this Can I then…
Mark Robinson
  • 3,135
  • 1
  • 22
  • 37
0
votes
1 answer

Composite Component and setPropertyActionListener

I have a composite component that have a dialog... Inside the dialog I have the following piece of code:
Marco Noronha
  • 115
  • 1
  • 9
  • 31
0
votes
1 answer

Update a value pased as a parameter in a composite component

I use this questions to create a composite component with the behaviour of a time selector. This is my composite xhtml
Arturo Volpe
  • 3,442
  • 3
  • 25
  • 40
0
votes
2 answers

Layout problems with composite components and PanelGrid

Possible Duplicate: How to make a grid of JSF composite component? I have a with one column to produce the header and the footer. The text is in Portuguese, it says "Fields are placed here! PS: inside the secound panel". Inside…
Marco Noronha
  • 115
  • 1
  • 9
  • 31
0
votes
1 answer

JSF2: NullpointerException at custom composite component

I've been trying to create an own component to "replace" the Richfaces spacer, which is no longer available in Richfaces 4. I have found this link for the actual implementation:…
Nizor
  • 85
  • 2
  • 9
0
votes
1 answer

composite component button action issue in jsf2 mojarra

Trying to develop a composite component using jsf2.0 (Mojarra) which should render command buttons dynamically based on the list from the bean. I was able to render the buttons but action is not getting triggered.Could any one please help me to…
Sathya Elangovan
  • 163
  • 3
  • 14
0
votes
1 answer

How to correctly wrap richfaces panel inside a composite components named div

I tried to write in resources/ui/div.xhtml:
johan.i.zahri
  • 316
  • 6
  • 18
0
votes
1 answer

JSF composite:actionSource in nested composite components

According to the JSF documentation for : Nesting of composite components The implementation must support nesting of composite components. Specifically, it must be possible for the section of a composite component to act as…
Lucas
  • 14,227
  • 9
  • 74
  • 124