pass bean action as attribute in custom tag inside ui:repeat [duplicate] - jsf

In my JSF 1.2 project, I have created a facelet tag file and defined an inputText that has actionListener attribute to which I need to pass the backing bean method name.
I tried defining a variable actionListener="#{actionListener}" in the tag file. In my xhtml where I call the component, when I pass the value as
actionListener="#{myBean.preFillData}"
tag file treats it as a property and errors out indicating no property 'preFillData' found. If I change it to
actionListener="#{myBean.preFillData()}"
then there is a parse error in the tag file because it doesnot like parenthesis to indicate method name.
How do we pass method name to the tag file?
Thanks
PT

Passing method expressions is not supported in tag files. Only since JSF 2.0 it's possible with so-called composite components.
What you can do is to separate the bean reference and the method name so that you can use the brace notation to invoke the method. I'm only not sure if that works out for an actionListener, you normally don't use that to invoke actions, but it should definitely work for an action.
E.g.
<my:tag ... bean="#{myBean}" actionMethod="preFillData" />
with inside tag.xhtml
<h:commandButton ... action="#{bean[actionMethod]}" />
Only if you happen to use JSF 2.0 on Facelets, then you can use <o:methodParam> to pass a method expression to a tag file. See also a.o. Dynamic ui include and commandButton.

Related

What exactly is #{component} in EL?

According to https://code.google.com/p/primefaces/issues/detail?id=4720, The ComponentUtils.resolveWidgetVar(String expression, UIComponent component) function is available in Primefaces since 2013. It can be used in EL by the "#{p:widgetVarFromContext(searchExpression, component)}" function.
This is useful in case of several components have the same id in different NamingContainer, but are still present in the same view. In this case,
the #{p:widgetVar(searchExpression)} function only returns the last one found.
I don't understand however how to reference the UIComponent that must be passed as the second argument from EL. The above mentioned bug report suggests we can refer to it using #{component}. Can anyone provide me with an example?
The #{component} is an implicit EL variable referring the current UIComponent in EL scope (see also implicit EL objects). You can usually only refer it in component's HTML attribute or in template text children.
E.g. in case of <h:inputText> it will reference an instance of UIInput class which has among others an isValid() method.
<h:inputText id="foo" required="true"
style="background: #{component.valid ? '' : 'pink'}"
onclick="alert('Client ID of this component is #{component.clientId}');" />
You can also use binding attribute to let JSF during view build time put a reference to a component instance in the Facelet scope. This way the component reference will be available anywhere in the Facelet during view render time.
<script>alert('Client ID of foo component is #{foo.clientId}');</script>
<h:inputText binding="#{foo}" />
See also:
Difference between client id generated by component.clientId and p:component()
JSF component binding without bean property
How does the 'binding' attribute work in JSF? When and how should it be used?
The p:widgetVarFromContext is useful when referring to a PrimeFaces widget inside a composite component. There could be more than one instance of your component on the same page. So writing widgetVar="expression" and PF('expression') is out of the question. There would be multiple widgets with the same name. It is then better to omit the widgetVar attribute and use the generated one which is unique because it is based on the clientId.
You can't use #{p:widgetVar('expression')} within your <cc:implementation> because it leads to a Cannot find component for expression "expression" referenced from "j_id1" error instead of the expected PF('widget_expression').
But you can use #{p:widgetVarFromContext('expression', cc)} which will return something like PF('widget_wrapperform_compositecomponent1_expression'). The cc refers to the root of the composite component instance.

How to invoke a managed bean action method in on* attribute of a JSF component

I'd like to invoke a managed bean action method in an on* attribute. In my particular case I need to logout an user if the user is idle for 3 minutes as below:
<p:idleMonitor onidle="#{mybean.processTimeOut()}" timeout="180000" />
However, the managed bean action method is immediately invoked as the page loads. How is this caused and how can I solve it?
Like as all other on* attributes on all JSF components, the onidle attribute must represent a JavaScript callback, not a JSF backing bean action method. Any EL expressions in on* attributes would be evaluated immediately as String value expressions during generating the HTML output in expectation that they print (part of) JavaScript code.
It's exactly like as if you're doing <h:outputText value="#{mybean.processTimeout()}">. If you had removed the parentheses (), you'd have faced a PropertyNotFoundException which was also a hint at its own of it being evaluated as a value expression instead of a method expression.
In order to invoke a JSF backing bean method using JavaScript, you need an additional <p:remoteCommand>.
<p:idleMonitor onidle="processTimeout()" timeout="180000" />
<p:remoteCommand name="processTimeout" action="#{mybean.processTimeOut}" />
If you're not on PrimeFaces, head to the alternatives posted in this related answer: How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

JSF set property on ManagedBean in included Faceltes page

I am new to JSF and getting very confused doing something trivial. I am making up this example here to elaborate what I am want to do:
I have a xhtml fragment, say, stockQuoteFragment.xhtml, which is backed by a ManagedBean, say, StockQuoteService.java. StockQuoteService.java has property stockID and a method getStockQuote() which has all the logic to get the stockQuote for the value set on stockID property. stockQuoteFragment.xhtml displays #stockQuoteService.stockQuote.
Now I have another page Home.xhtml page with backing bean HomeBackingBean.java with a method getUserFavoriteStockID(). I want to include content of stockQuoteFragment.xhtml in Home.xhtml passing in the value of #homeBackingBean.userFavoriteStockID to StockQuoteService.setStockID().
I am not sure how to do this in JSF/Facelets. With simple JSPs I could do this easily with a JSP include and include parameters
No.
...According to TLD or attribute directive in tag file, attribute var does not accept any expressions.
I have just tried it.
But if you use pure XML based JSF with tags, you can easily use <ui:param> as discussed here. I use JSF in JSP and for me there is no help (<c:set> is mostly useless).
Can I just do this in Home.xhtml before I ui:include stockQuoteFragment.xhtml into it:
<c:set var="#{StockQuoteService.stockID}" value="#homeBackingBean.userFavoriteStockID"/>
will that work?

Passing valueChangeListener method expression into tag file

I have a <h:inputText> with an event listener like following:
<h:inputText valueChangeListener="#{myBean.handle}"/>
I would like to put it in a tag file which is to be used as follows:
<my:itext changeListener="#{myBean.handle}" />
With inside the tag file:
<h:inputText valueChangeListener="#{changeListener}" />
However it's evaluating it as a property instead of as a listener method. How can I pass the listener method into a tag file?
You can by design not pass method expressions as a tag file attribute. You basically need to convert the ValueExpression to a MethodExpression inside the tag file.
For JSF 2.x Facelets, this can be solved using OmniFaces <o:methodParam>.
<o:methodParam name="changeListenerMethod" value="#{changeListener}" />
<h:inputText valueChangeListener="#{changeListenerMethod}" />
However, for old and deprecated Facelets 1.x or JSP 2.x there is no existing solution. The OmniFaces <o:methodParam> is however open source, you should be able to copy and alter it for Facelets 1.x or JSP if necessary.
Note that when you're actually already using JSF 2.x, you could also use a composite component instead. This supports passing method expressions as <cc:attribute method-signature>. For JSF 1.x you can alternatively also create a real custom component, but that's a bit more work than just some XML.

Jsf dynamically created actionListener parameter

I have a custom facelet component (custom tag) but there is one thing that currently annoys me a lot. I'm trying to pass an action listener as a parameter to the custom tag, in order to make it more dynamic and just doesn't work.
Environment: JSF 1.2, IceFaces 1.8
Here's the way I'm trying to achieve this:
the command link uses the passed parameter 'paginationController'
<h:commandLink id="#{id}-link-three" value="click"
actionListener="#{paginationController.paginationLinkClicked}" />
the parameter 'paginationController' is passed like this:
paginationController="rowSelectController"
when I click the link, there's what I receive:
Received 'javax.el.MethodNotFoundException' when invoking action listener
'#{paginationController.paginationLinkClicked}' for component 'entity-list-apps-link-three'
2011-02-22 12:49:47,803 SEVERE [javax.faces.event] (http-127.0.0.1-8080-4)
javax.el.MethodNotFoundException: /WEB-INF/jsf/common/components/facelets
/applicationList.xhtml #107,71 actionListener="#{paginationController.paginationLinkClicked}":
Method not found: rowSelectController.paginationLinkClicked(javax.faces.event.ActionEvent)
So it seems that it successfully resolves the bean name to rowSelectController, but it complaints it can't find the method, and the method IS there!
One more thing, if I replace the parameter with the correct controller's name, it just works! Any ideas?
Because paginationController is variable you need to use the [] syntax here. Assuming paginationLinkClicked is a fixed method name:
<h:commandLink actionListener="#{paginationController['paginationLinkClicked']}" />
If paginationLinkClicked would also be variable, you need to omit the single quotes:
<h:commandLink actionListener="#{paginationController[paginationLinkClicked]}" />

Resources