Expose items of a list while iterating within composite component
Asked Answered
O

2

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>
Osteen answered 17/6, 2012 at 12:51 Comment(0)
G
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>
Geodetic answered 17/6, 2012 at 14:24 Comment(9)
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 ?Osteen
The same way as in your question. All you need is replacing <ui:repeat> by <c:forEach>.Geodetic
Actually #{listRetriever.list} is built using <f:event type="preRenderComponent" listener="#{cc.attrs.fetchMethod}"/>, I guess this would occur after the c:forEach loop has completed iterating, so that's why it is not working for me..Osteen
so is there any other way to do this avoiding the JSTL altogether ?Osteen
Why exactly isn't that job been done in the (post)constructor?Geodetic
because listRetriever bean is used to fetch different types of list in different contexts.. it is multipurpose.. so it cannot be built in postconstruct methodOsteen
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 ?Osteen
thoughts on this ? The solution you rejected, does seem to work.. Did i missed out anything ?Osteen
The original code is working and actually is exactly what is suggested in this answer. This is the opposite form what BalusC suggestes... and this confuses me. What is the correct way of doing it?Georgia
O
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>

Overdye answered 19/6, 2012 at 19:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.