1

I'm iterating over a list of items in composite component. I want to expose each item of the list so that they could be used within the child component of this composite component, to create a template for how to display all items in the list.

Here is my Composite Component implementation:

customList.xhtml

<ui:component
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:cc="http://java.sun.com/jsf/composite"
    xmlns:ui="http://java.sun.com/jsf/facelets">    

    <cc:interface>
    </cc:interface>

    <cc:implementation>       
        ...
        ...   
        <ui:repeat value="#{listRetriever.list}" var="item">
            <cc:insertChildren />
        </ui:repeat>

    </cc:implementation>
</ui:component>

Now I want to make use of #{item} while defining the child component of composite component in my page (similar to h:dataTable or ui:repeat).

  <my:customList>
        #{item}                <!--- over here--->
  </my:customList>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Rajat Gupta
  • 25,853
  • 63
  • 179
  • 294

2 Answers2

2

That won't work with <cc:insertChildren> inside <ui:repeat> as the <cc:insertChildren> is evaluated during view build time, not during view render time. The #{item} is only available during view render time as the <ui:repeat> runs during view render time only.

It'll work when you use JSTL <c:forEach> instead as it's also evaluated during view build time like the <cc:insertChildren> itself.

xmlns:c="http://java.sun.com/jsp/jstl/core"
...
<c:forEach items="#{listRetriever.list}" var="item">
    <cc:insertChildren />
</c:forEach>

Be careful when you use the composite in turn inside another repeating JSF component, it wouldn't work then. See also JSTL in JSF2 Facelets... makes sense?.

An alternative, apart from creating a custom component which extends UIData or UIRepeat, is using <ui:decorate> instead.

First make customList.xhtml a normal template:

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
>
    ... 
    ...  
    <ui:repeat value="#{list}" var="item">
        <ui:insert name="item" />
    </ui:repeat>
    ...
    ...
</ui:composition>

Then you can use it as follows:

<ui:decorate template="customList.xhtml">
    <ui:param name="list" value="#{bean.list}" />
    <ui:define name="item">
        #{item}
    </ui:define>
</ui:decorate>
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • just template using `ui:decorate` is not what I want since I'm trying to add more functionality like lazy load etc(omitted here for simplicity). Regarding `c:forEach` how do I expose the #{item} defined within CC to be used on the page where I'm using the CC ? – Rajat Gupta Jun 17 '12 at 15:34
  • The same way as in your question. All you need is replacing `` by ``. – BalusC Jun 17 '12 at 15:35
  • Actually `#{listRetriever.list}` is built using ``, I guess this would occur after the `c:forEach` loop has completed iterating, so that's why it is not working for me.. – Rajat Gupta Jun 17 '12 at 18:03
  • so is there any other way to do this avoiding the JSTL altogether ? – Rajat Gupta Jun 17 '12 at 18:06
  • Why exactly isn't that job been done in the (post)constructor? – BalusC Jun 17 '12 at 20:57
  • because `listRetriever` bean is used to fetch different types of list in different contexts.. it is multipurpose.. so it cannot be built in postconstruct method – Rajat Gupta Jun 18 '12 at 03:28
  • I dont know how, but the solution that I proposed in the question & what @Huevo also proposed through his answer just seem to work with ui:repeat as it is, which seems to contradict the statements in your answer, how could please clarify upon this ? – Rajat Gupta Jun 30 '12 at 17:41
  • thoughts on this ? The solution you rejected, does seem to work.. Did i missed out anything ? – Rajat Gupta Jul 02 '12 at 02:28
  • The original code is working and actually is exactly what is suggested in [this answer](http://stackoverflow.com/questions/13356967/jsf-iterative-composite-component-with-customizable-content#13357590). This is the opposite form what BalusC suggestes... and this confuses me. What is the correct way of doing it? – Martin Höller Aug 06 '14 at 11:48
1

These days I've tried to do something similar, unresolved.

My solution, the value of the var attribute on my own compononent never can do it configurable. So stay fixed under the name "var", and always expose to my component and I use the variable "var".

Example of mi code:

Component: file:listadoPaginado.xhtml

<composite:interface>
    <composite:attribute name="id" required="true" 
                         displayName="ID if component" 
                         shortDescription="ID of component" />
    <composite:attribute name="value" required="true" 
                         displayName="List with values to iterate"/>  
</composite:interface>

<!-- Implementacion de la estructura del componente -->
<composite:implementation>
    <h:panelGroup id="#{cc.attrs.id}_panel_comp">
        <br/>
        <div  style="#{cc.attrs.style}">

            <ui:repeat  var="var" value="#{cc.attrs.value.model}">
                <composite:insertChildren/>
            </ui:repeat>
        </div>
    </h:panelGroup>
</composite:implementation>

Use of Component:

<gb:listadoPaginado id="listado_garantias"
                            value="#{beanTest.myList}">
 <p:panel>
     <p:panelGrid>
         <p:row>
              <p:column>
                   <h:outputLabel value="#{var.description}"/>
               </p:column>
               <p:column>
                    <p:inputText value="#{var.longDescription}"/>
                </p:column>
          </p:row>
       </p:panelGrid>
   </p:panel>