Pass actionListener method to commandButton within a component - jsf

first, please forgive my ignorance and inability so use the search engine (i swear i have searched long and often but did not find any satisfying answer to this problem).
I have a bean implementing a action-listener compatible method:
#ManagedBean(name = "myBean")
#ViewScoped
class Bean{
public String myAction(ActionEvent event){
... = event.getComponent().getAttributes().get("something");
}
}
Then, i have a jsf component like this:
<composite:interface>
<composite:attribute name="actionBean" required="true"/>
<composite:attribute name="actionMethod" method-signature="void myAction(javax.faces.event.ActionEvent)" />
</composite:interface>
<composite:implementation>
<h:form>
<p:commandButton actionListener="#{cc.attrs.actionBean[cc.attrs.actionMethod]}">
<f:attribute name="something" value="somevalue" />
</p:commandButton>
</h:form>
</composite:implementation>
It is called something like this:
<namespace:myComponent actionBean="#{myBean}" actionMethod="myAction" />
I know that this call is not working, and i wonder how to do it right!
My main intention is that i want to have a relatively generic jsf-component (would be nice to have it reusable later), that contains a button. On click to this button i want to pass an object (no simple string! in case of string i would just use action="..." and pass it via f:param). With the actionListener method i take the object via event.getComponent().getAttributes().get("something").
I think the signature void myAction(javax.faces.event.ActionEvent) is the problem that breaks passing the related method to the component, isnt it? Is it in general possible to pass method with any argument to jsf components (and if yes, how)?
So, i hope there is a possible solution to solve the general problem with altering the above strategy or maybe use something nice and different (in general i prefer not to use any hacks or workarounds, but like to use what is intended by the framework).
Thanks if somebody would find the time to point me the way! In case this question already exists, would be nice to get to the related post and have this deleted.

Try following:
<namespace:myComponent myAction="#{myBean.myAction}"/>
And composite component:
<composite:interface>
<composite:attribute name="myAction"
required="true"
method-signature="void myAction(javax.faces.event.ActionEvent)"
targetAttributeName="actionListener"/>
</composite:interface>
<composite:implementation>
<h:form>
<p:commandButton id="myAction">
<f:attribute name="something" value="somevalue" />
</p:commandButton>
</h:form>
</composite:implementation>
Check composite:attribute documentation. It has several options to pass listeners to composite component. I used targetAttributeName for this.

Related

How to reference component inside a composite component when using a converter

I have a composite component that mainly consists of a selectManyCheckbox component. As it should be designed in a generic way I pass in selectItems, ajax handling etc. from the calling level using
<composite:insertChildren/>
This works quite well for most of the stuff. Now I need to use this composite component with a converter. As the converter (a kind of Omnifaces' ListConverter) is not needed all the time (sometimes I want to have the value-binding of concrete entities that back the select items, sometimes I don't), I'd like to pass it in as the parts mentioned before (e.g. selectItems, ajax event handling).
Given this it is necessary to use the converter tag's 'for' attribute to reference the component inside the composite component. At least that is what I understand.
Unfortunately I have no idea what value should be used. Do I have to include the name of the composite component (naming container)? Do I have to use the clientId? I have tried a lot of combinations but the converter has not been invoked. As soon as I put the converter tag inside the composite component definition, it works.
To make things easier, let's assume I have the following:
<composite:interface>
<composite:attribute name="value" required="true"/>
</composite:interface>
<composite:implementation>
[...]
<h:selectManyCheckbox id="#{cc.attrs.id}" value="#{cc.attrs.value}">
<composite:insertChildren/>
</h:selectManyCheckbox>
[...]
</composite:implementation>
This component should be used as follows:
<my:selectManyCheckbox id="myComponent" value="...">
<f:selectItems value="..."/>
<o:converter for="___" converterId="..."/>
</my:selectManyCheckbox>
Perhaps someone can give me a hint what value should be given to the 'for' attribute.
I found the answer myself. You can use the following
<composite:interface>
<composite:attribute name="value" required="true"/>
<composite:editableValueHolder name="input_component">
</composite:interface>
<composite:implementation>
[...]
<h:selectManyCheckbox id="input_component" value="#{cc.attrs.value}">
<composite:insertChildren/>
</h:selectManyCheckbox>
[...]
</composite:implementation>
The important part is the editableValueHolder tag. From the page using this composite component, you can now use
<o:converter for="input_component" converterId="id_of_converter" />
This is the solution that is working for me. I hope this helps others having the same problem.

Send parameter to request on every action for composite component

I have a composite component, which has an id I would like to send as a parameter when executing one of many posiible actions inside the composite component. I know I can use something like;
<h:form id="testForm">
<p:commandButton value="#{testReqBean.label}"
actionListener="#{testReqBean.perform()}"
process="#this or #form" update="#form" ajax="true" >
<f:param value="#{cc.attrs.id}" name="CC-Id" />
</p:commandButton>
</h:form>
now, imagine I have many forms or buttons with specific actions inside the composite component... is there a way to define the parameter I want to send in the request just once ? I mean not adding an f:param inside each form/button (depending on the process #form or #this) but one for the whole composite component?
Thanks in advance!
Maybe one solution would be to use viewparam but this only works if you can add a request parameter.
<f:metadata>
<f:viewParam value="#{your_bean.your_property_name}" name="request_param"/>
</f:metadata>
The only problem here is that whoever implements your composite component would have to set the above when needed, but it still an abstraction to this problem of having to set the same property for all components in same page.
I gather that the <h:form> is enclosed in the composite component itself.
Just use a plain HTML hidden input field.
<h:form>
<input type="hidden" name="CC-Id" value="#{cc.attrs.id}" />
...
<p:commandButton />
<p:commandButton />
<p:commandButton />
...
</h:form>
Unrelated to the concrete problem, having an entire form in a composite is kind of strange. This is then food for read: When to use <ui:include>, tag files, composite components and/or custom components?

setPropertyActionListeners to composite component

I need to create composite component containing two h:commandLinks. And i want to pass f:setPropertyActionListeners from the client-code to be applied to both two commandLinks. Is this ever possible? I tried to use cc:insertChildren, but appropriate setters are not being fired.
<my:operationLink action="#{cc.attrs.bean.myAction}">
<f:setPropertyActionListener for="<!-- whats here? -->" value="#{cc.attrs.someAttrOne}" target="#{cc.attrs.bean.someAttrTargetOne}"/>
<f:setPropertyActionListener for="<!-- whats here? -->" value="#{cc.attrs.someAttrTwo}" target="#{cc.attrs.bean.someAttrTargetTwo}"/>
and my component:
<cc:implementation>
<h:commandLink id="textLink" value="myTextLink"><ui:insert/></h:commandLink>
<h:commandLink id="imgLink"><h:graphicImage url="/images/my.gif"/><ui:insert/></h:commandLink>
i need to apply actionlisteners to both links ( into ui:insert)
You need to declare a <cc:actionSource> in the composite interface with the "event name" in name (e.g. actionEvent, this is fully arbitrary to your choice) and the client IDs of those command links space separated in the targets.
<cc:interface>
<cc:actionSource name="actionEvent" targets="textLink imgLink" />
</cc:interface>
Then you can use in the client:
<f:setPropertyActionListener for="actionEvent" ... />
Don't forget to remove <ui:insert>. This is indeed definitely not the right way.

Passing EL method expression as attribute of custom Facelets tagfile

I created a custom JSF tag:
<ui:composition>
<h:panelGroup>
<rich:dataScroller id="#{id}" for="#{table}" execute="#{table}"
page="#{scrollerPage}" render="#{table}-sc1" maxPages="5"
fastControls="hide" oncomplete="#{onCompl}" scrollListener="#{scrollListenerBean[scrollListenerMethod]}" />
<h:inputText value="#{scrollerPage}" id="#{table}-sc1" size="2">
<f:convertNumber integerOnly="true" />
</h:inputText>
<h:outputText styleClass="outputText"
value=" of #{scrollPagesCount} " />
<h:commandButton value="GO! " />
</h:panelGroup>
</ui:composition>
To pass the listener method, I used the solution suggested in a quite old blog:
<my:dataScroller id="idDS1" table="table1"
scrollerPage="#{bean.navigationHelper.scrollerPage}"
scrollPagesCount="#{bean.navigationHelper.scrollPagesCount}"
onCompl="initForm();"
scrollListenerBean="#{bean}"
scrollListenerMethod="aMethod" />
My questions are: is this the best way to do this? How can I make the method optional?
Thanks a lot for any Help! bye!
My questions are: is this the best way to do this?
That's the only way anyway, provided that you can only use standard JSF/EL facilities and you cannot create a custom taghandler.
You could however create a custom taghandler to convert the value expression to a method expression. The OmniFaces JSF utility library has a <o:methodParam> for exactly this purpose. See also the <o:methodParam> demo page.
You could then end up like:
<my:dataScroller ... scrollListener="#{bean.aMethod}" />
and
<o:methodParam name="scrollListenerMethod" value="#{scrollListener}" />
<rich:dataScroller ... scrollListener="#{scrollListenerMethod}" />
See also:
Dynamic ui include and commandButton
How can I make the method optional?
Theoretically, you could use JSTL tags to build the view conditionally. Something like:
<h:someComponent>
<c:if test="#{not empty fooAttribute}">
<f:attribute name="foo" value="#{fooAttriubte}" />
</c:if>
</h:someComponent>
But that's in the particular case of a special method expression listener attribute unfortunately not possible. There's no such thing as <rich:scrollListener> or something which allows you binding a RichFaces specific scrollListener as a separate tag to the <rich:dataScroller>. Best what you could do without creating custom taghandlers is duplicating the whole <rich:dataScroller> in two <c:if>s (or a <c:choose>); one with and other without scrollListener. This is too clumsy. You'd really better create a custom <my:richScrollListener> taghandler for this which you could then place in a <c:if>.

JSF 2 composite component, passing attributes to backing bean

I'm stuck on simple JSF2 question:
XHTML:
<xvf:simpleOut identifier="12345"/>
Composite component is supposed to pass "12345" to backing bean and do some output:
<composite:interface>
<composite:attribute name="identifier" required="true" type="java.lang.String"/>
</composite:interface>
<composite:implementation>
<!--#elvariable id="arg" type="java.lang.String"-->
<ui:param name="arg" value="#{cc.attrs.identifier}"/>
<h:outputText value="#{myBean.getTestOutput('???????')}"/>
</composite:implementation>
How do I pass identifier value, '12345' in my case, to bean's getTestOutput(String arg) method?
You don't need the <ui:param> tag at all. This should work:
<h:outputText value="#{myBean.getTestOutput(cc.attrs.identifier)}"/>
But it might a a good idea to pass myBean through the interface as well rather than refering to it directly, since it would make the composite component reusable.

Resources