0

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?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Pablo
  • 3,433
  • 7
  • 44
  • 62
  • Does it work outside the composite then? If I'm not wrong, you should have used `` instead. – BalusC Mar 24 '12 at 12:57
  • Mmm when I use c:forEach like this: It doesn't even call the getter for the items attribute... – Pablo Mar 26 '12 at 14:50
  • I don't use RichFaces closely, but if I'm not wrong, using `ui:repeat` to generate `rich:menuItem` wouldn't even have worked outside the composite. You should have used the `c:forEach` for that. But inside the composite itself, the `c:forEach` in turn wouldn't work when the `items` attribute depends on JSF render time attribute (e.g. obtained from the `var` of another parent `ui:repeat` or `h:dataTable`). I think a tag file is for you after all easier. – BalusC Mar 26 '12 at 14:54
  • I'm sorry BalusC, I made a mistake and got a null pointer exception when trying the c:forEach inside the component. However when I realized this it worked... althought I haven't tested using ajax render attributes on my component. Also something I noticed is that the getter is called 4 times when using c:forEach... why is this? And why I can't use a4j:repeat or ui:repeat inside a composite?. Anyways thanks a lot BalusC, you really helped me. Thanks. – Pablo Mar 26 '12 at 15:19

2 Answers2

1

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.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
1

As long as i know an attribute being used in an 'action' tag-attribute must be defined as a method in the composite interface; i.e using the tag-attribute 'method-signature' in the definition of the composite component attribute.