I'm creating a composite component in JSF 2..., inside it I have defined a controller attribute which should point to a custom object which handles the logic behind the component.
Basically the component has a dropdownMenu that's created dynamically based on some options provided by the controller.
I tried something like this:
<composite:interface>
<composite:attribute name="id" required="true" />
<composite:attribute name="controller" required="true"/>
</composite:interface>
<composite:implementation>
<a4j:outputPanel layout="block" id="pnlTaskOptions" style="width:300px;">
<rich:dropDownMenu mode="ajax">
<f:facet name="label">
<h:panelGroup layout="block" styleClass="botonA" rendered="true">
<h:outputLink styleClass="solicitarAutorizacionA"
value="#{msg_autweb['etiqueta.aprobar']}"
immediate="true"/>
</h:panelGroup>
</f:facet>
<a4j:repeat value="#{cc.attrs.controller.taskOptions}" var="option">
<rich:menuItem label="opcion"
action="#{cc.attrs.controller.executeOption(option)}"
render="pnlTaskOptions">
</rich:menuItem>
</a4j:repeat>
</rich:dropDownMenu>
</a4j:outputPanel>
</composite:implementation>
cc.attrs.controller.taskOptions is an String arrayList that's filled inside the controller's constructor.
I have debugged the getters of it, and checked that the array was being retrieved correctly, in other words checked that it wasn't empty.
However the menu didn't appear, like if there were no children menu items. What's going on? Isn't possible to use a a4j:repeat inside a composite component?
The <a4j:repeat>
and <ui:repeat>
are UI components which runs at JSF HTML render time. All its children will generate HTML multiple times as many times as the component needs to iterate over the supplied collection. Note that there's physically only one component in the JSF component tree. The <c:forEach>
is a tag file which runs at JSF view build time. The JSF component tree will end up with as many duplicated children as the tag needs to iterate over the supplied collection. Each of those duplicated children generates HTML only once.
In your initial approach, you end up with <rich:dropdownMenu>
which has only one child of type <a4j:repeat>
which in turn has only one child of <rich:menuItem>
. This is not supported by <rich:dropdownMenu>
. This component supports only multiple children of type <rich:menuItem>
.
So, replace <a4j:repeat>
by <c:forEach>
and it should work.
You only need to ensure that its value in turn should not depend on the value of some parent iterating UI component, or it will fail again. In such case, you really need a tag file instead of a composite component.