16

The title really says it all. I have made an attempt which failed with the error:

Illegal attempt to pass arguments to a composite component lookup expression (i.e. cc.attrs.[identifier]).

My attempt looks like this:

<composite:interface>
  <composite:attribute name="removeFieldAction" method-signature="void action(java.lang.String)" />
</composite:interface>
<composite:implementation>
  <h:commandButton value="Remove" action="#{cc.attrs.removeFieldAction('SomeString')}"/>
</composite:implementation>

What's the right way to do this?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Ben
  • 10,020
  • 21
  • 94
  • 157

1 Answers1

37

This is indeed not going to work. You cannot pass "extra" parameters afterwards like that. The method-signature as you have declared has to be fulfilled in the side where the composite component is been used. E.g.

<my:button action="#{bean.remove('Somestring')}" />

The composite component implementation should just look like this

<h:commandButton value="Remove" action="#{cc.attrs.removeFieldAction}" />

If this is not what you want and you really want to pass it from the composite component side on, then I can think of two ways of passing extra arguments: using <f:attribute> with an action listener to pass it as an attidional component attribute, or <f:setPropertyActionListner> to let JSF set it as a property right before the action is invoked. But none of both are without changes in the composite component. You would need to request for at least the whole bean as an attribute of the composite component.

Here's an example with <f:setPropertyActionListener>. This sets property right before the action is been invoked.

<composite:interface>
    <composite:attribute name="bean" type="java.lang.Object" />
    <composite:attribute name="action" type="java.lang.String" />
    <composite:attribute name="property" type="java.lang.String" />
</composite:interface>
<composite:implementation>
    <h:commandButton value="Remove" action="#{cc.attrs.bean[cc.attrs.action]}">
        <f:setPropertyActionListener target="#{cc.attrs.bean[cc.attrs.property]}" value="Somestring" />
    </h:commandButton>
</composite:implementation>

which is to be used as

<my:button bean="#{bean}" action="removeFieldAction" property="someString" />

With the above example, the bean should look like

public class Bean {

    private String someString;

    public void removeFieldAction() {
        System.out.println(someString); // Somestring
        // ...
    }

    // ...
}

If you adhere a specific convention, you can maybe even omit the property attribute altogether.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Tnx. The Idea is that the composite component creates a list of fields with each field being linked to an object in the bean. Once a field is removed from the UI, the bean must be notified of the ID of the removed field so it will be removed from the bean as well. Hence, the `someString` parameter is, in fact, the UUID of the removed field. I am, in practice, trying to achieve something similar to an event listener with an argument... Thanks for the solution! – Ben Jun 15 '11 at 12:25
  • 1
    Hi BalusC. Thank you much for this reply. This works on Mojarra but does not seems to work on MyFaces. I posted a separate issue here, will you please have a look when u have time please? http://stackoverflow.com/questions/17357593/passed-argument-to-method-inside-composite-component-does-not-work-on-myfaces Thank you very much – Thang Pham Jun 28 '13 at 05:09
  • 2
    is this still relevant? it's cumbersome and there should be a better way to return values from a composite component @BalusC – alibttb May 07 '19 at 17:47