Passing parameters to a method in h:outputtext tag - jsf

I would like to display a text in jsf screen by passing an attribute to a method implemented in backing bean. I have to pass a dynamic value as an attribute. I tried the below but it seems to be an incorrect syntax -
<h:outputText value="#{getValue(#{item.product}).component.address}" />

Apart from the syntax error (you can never nest EL expressions like as #{#{}}), the following is valid in EL 2.2 which is in turn part of Servlet 3.0 / Java EE 6:
<h:outputText value="#{bean.getValue(item.product).component.address}" />
So if you have a Servlet 3.0 compatible target runtime (Tomcat 7, Glassfish 3, JBoss 6, etc) with a Servlet 3.0 compatible web.xml, then you can invoke non-getter methods with arguments like this.
However, based on your question history you're using JSF 1.2 and the chance is big that you're also targeting an older container where the above wouldn't work. If it is a Servlet 2.5 container, then you could use JBoss EL to get this EL syntax to work.
See also:
Invoking methods with parameters by EL in JSF 1.2

JSF 1.2 w/ EL 2.1 (the usual pairing) doesn't support calling methods with parameters on beans using EL expressions.
There exists one hack, abusing the fact that JSF EL expressions work on maps:
value="#{myBean['product']}"
This will assume myBean is implementing Map interface and will call get method with 'product' as parameter. I don't know if the key can be dynamically computed but it's worth a try.
Syntax would be:
value="#{myBean[item.product].component.address}"
Assuming here that myBean implements Map interface and returns the appropriate object and item.product is returns a string.
I am not sure this will work, but it's your only option beside implementing a getter that looks up item.product value in its implementation.

Related

Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?

I'm using Glassfish 3.1.2.2 and JSF Mojarra 2.1.6.
I have the following Facelets page:
<h:form>
<h:commandLink value="link">
<f:actionListener binding="#{backingBean.someMethod(1)}"/>
</h:commandLink>
</h:form>
And the following backing-bean:
#RequestScoped
#ManagedBean
public class BackingBean {
public void someMethod(int i) {
System.out.println("It was called: " + i);
}
}
When I click the link, "Info: It was called: 1" appears in the console.
The documentation for binding reads:
Library: http://xmlns.jcp.org/jsf/core, http://java.sun.com/jsf/core (Jsf Core)
Tag: actionListener
binding
Value binding expression that evaluates to an object that implements javax.faces.event.ActionListener. [emphasis mine]
Also, the accepted answer to this question states that it's not possible for an f:actionListener to call an arbitrary method.
Why is the backing bean method called if this isn't supported?
This is the consequence of the new EL 2.2 feature of calling a method in a value expression via the #{bean.method()} syntax instead of only referencing a property via the #{bean.property} syntax (which should indeed be of the exact type ActionListener). It wouldn't have worked in EL 2.1 or older and it would also not work when you remove the arguments and the parentheses. That document was written when EL 2.2 didn't exist (it's actually not modified as compared to JSF 1.2 version from May 2006; EL 2.2 was introduced December 2009). I however do agree that it needs an update on that part as it's confusing to starters.
The answer you found made its points based on the document, but the answerer however didn't seem to realize based on the question that while binding="#{testController.nodeListener}" failed, the binding="#{testController.nodeListener(event)}" actually worked. This only doesn't give you the opportunity to pass the ActionEvent. The answer was better if it suggested to just use binding="#{testController.nodeListener()}" instead and grab the event information in other way, such as by calling UIComponent#getCurrentComponent() or even by passing #{component} as argument. Only if you really need to have a hand of it, of course.
<h:commandLink value="link">
<f:actionListener binding="#{bean.someMethod(component)}"/>
</h:commandLink>
public void someMethod(UIComponent component) {
System.out.println("It was called on: " + component); // HtmlCommandLink
}
See also:
Invoke direct methods or methods with arguments / variables / parameters in EL
Difference between JSP EL, JSF EL and Unified EL
Differences between action and actionListener

role attribute of h:panelGrid

I'm using exaples from the official Java EE tutorial In which contains the follow:
<h:panelGrid columns="2"
headerClass="list-header"
styleClass="list-background"
rowClasses="list-row-even, list-row-odd"
summary="#{bundle.CustomerInfo}"
title="#{bundle.Checkout}"
role="presentation">
But compiler says that attribute role is not defined for h:panelGrid component. How to fix this?
That attribute was introduced in JSF 2.2. As evidence, the role attribute is mentioned in JSF 2.2 <h:panelGrid> documentation, but not in JSF 2.1 <h:panelGrid> documentation.
Your question history confirms that you're using JSF 2.2 on GlassFish 4.0, so this compiler warning is actually wrong. This is not exactly a JSF problem, but an IDE problem. The IDE is somehow thinking that you're not using JSF 2.2, but JSF 2.1 or older. I.e. your toolset is working against you. You didn't mention which IDE you're using, so it's not possible to post the right answer.
If the project runs fine and the JSF page produces the right HTML output (i.e. the role attribute actually ends up in generated HTML <table> element as you can see by rightclick, View Source in webbrowser), then everything is well and it's just the IDE who's pretending to be smarter than it actually is.
I'd start peeking around in IDE project's properties to check if the JSF versions are all right. The JSF facet in project's properties must be set to version 2.2, not lower. The faces-config.xml must be declared conform JSF 2.2, not lower.

Migrating JSF 1.1 with Ajax4jsf 1.x to JSF 2

We are migrating JSF 1.1 (MyFaces) project to JSF 2. The idea is to migrate periodically by keeping both JSP and XHTML together for some time. We use many ajax4jsf-1.1.1 tags in JSP pages. We don't use RichFaces. After configuring the system to JSF 2 (with all config changes mentioned in tutorial by Balusc) When tried to access the JSP page with ajax4jsf.jar in classpath, we get an exception:
Caused by: java.lang.IllegalStateException: setViewHandler may not be executed after a lifecycle request has been completed
at org.apache.myfaces.application.ApplicationImpl.setViewHandler(ApplicationImpl.java:853)
at org.ajax4jsf.framework.ajax.InitPhaseListener.beforePhase(InitPhaseListener.java:92)
at org.apache.myfaces.lifecycle.PhaseListenerManager.informPhaseListenersBefore(PhaseListenerManager.java:76)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:131)
It looks ajax4jsf.jar is not compatible with JSF 2. Looks some issue with LifeCycle configuration.
Is there any way we can make a4j work with JSF 2 JSPs? I know when we use XHTML we don't need all this.
Get rid of Ajax4jsf 1.x altogether. It's indeed not compatible with JSF2. Instead, JSF2 offers a new main ajax tag <f:ajax> which covers all the core functionality as previously offered by Ajax4jsf 1.x.
If upgrading to RichFaces 4 is not an option (because, as you said yourself, you aren't using RichFaces components anywhere), then just remove Ajax4jsf 1.x and replace all <a4j:xxx> tags by standard JSF2 equivalents.
<a4j:ajaxListener>: use <f:ajax listener>.
<a4j:keepAlive>: just put managed bean in the view scope by #ViewScoped.
<a4j:log>: use jsf.ajax.addOnEvent() or jsf.ajax.addOnError() in JS context.
<a4j:commandLink>: just nest <f:ajax> inside <h:commandLink>.
<a4j:outputPanel>: use <h:panelGroup> and remember to include its ID in <f:ajax render> or PrimeFaces <p:outputPanel>.
<a4j:repeat>: just use standard <ui:repeat>.
<a4j:form>: just use <h:form>, it will autorecognize <f:ajax>.
<a4j:htmlCommandLink>: just nest <f:ajax> inside <h:commandLink>.
<a4j:jsFunction>: just use standard <h:commandScript>. It was however introduced late in JSF 2.3. If you can't upgrade to JSF 2.3 then consider OmniFaces <o:commandScript> or PrimeFaces <p:remoteCommand>.
<a4j:region>: just use <f:ajax execute>, you can even wrap <f:ajax> around a group of components.
<a4j:loadBundle>: just use standard <f:loadBundle>.
<a4j:status>: use jsf.ajax.addOnEvent() or jsf.ajax.addOnError() in JS context.
<a4j:actionparam>: just use standard <f:param>.
<a4j:loadScript>: just use standard <h:outputScript>.
<a4j:mediaOutput>: no replacement. Consider PrimeFaces <p:media>.
<a4j:poll>: no replacement. Consider OmniFaces <o:commandScript> or PrimeFaces <p:poll>.
<a4j:commandButton>: just nest <f:ajax> inside <h:commandButton>.
<a4j:include>: just use standard <ui:include>.
<a4j:loadStyle>: just use standard <h:outputStylesheet>.
<a4j:support>: just use standard <f:ajax>.
You also need to rename/rewrite JSP files to Facelets files. In simple cases, this is usually just a matter of changing root declarations and file extensions. Facelets makes it easier to replace all duplicated code by a single template. The following answer applies:
Migrating from JSF 1.2 to JSF 2.0

JSF - actionListener tag calls method which doesn't take an ActionEvent parameter

I keep reading posts which say that ActionListener methods must have the following signiture:
public void calledByActionListener(ActionEvent e) {
}
Invoked like so:
<p:commandButton value="Example" id="example" process="#this" ajax="false"
actionListener="#{exampleBean.calledByActionListener()}">
However I have a no-arg method like this which works:
public void calledByActionListener() {
}
Did something change?
Yes, that's the new EL 2.2 feature of invoking methods with custom arguments. Basically, you're explicitly invoking an argumentless method. This construct is legit.
Note that this is not related to JSF2. EL 2.2 just happens to be part of Java EE 6 as well like JSF2. So it look like a new JSF2 feature. But it actually isn't. As evidence, JSF2 is backwards compatible with Java EE 5 which thus implies EL 2.1, but this construct doesn't work over there.
When not explicitly specifying any custom arguments in the method expression, JSF will as per the specification assume a default argument of ActionEvent in the actual method.

Invoking methods with parameters by EL in JSF 1.2

I am using a datatable and for each row I have two buttons, an "Edit" and a "Delete".
I need these buttons to be read-only, i.e. disabled, if a certain condition is met for the row in question. I have seen in JSF 2 that it is possible to pass parameters to method calls. Is there anything equivalent in JSF 1.2?
Ideally what I would like it something like (the looping variable is loop and there is another bean, helper, which contains the method I would like to invoke):
<h:commandButton value="Edit"
disabled="#{helper.isEditable(loop.id)}" />
In this case it does not make semantic sense to add an isEditable attribute to the bean and it is not practical to create a wrapper Object around the bean.
Thanks in advance.
I have seen in JSF 2 that it is possible to pass parameters to method calls. Is there anything equivalent in JSF 1.2?
Passing parameters to method calls is not specific to JSF 2. It is specific to EL 2.2, which is in turn part of JSP 2.2 / Servlet 3.0 / Java EE 6. JSF 2 just happens to be part of Java EE 6 as well. In other words, if you deploy your JSF 1.2 web application to a Servlet 3.0 compatible container like Tomcat 7, Glassfish 3, etc and your web.xml is declared conform Servlet 3.0 spec version, then it'll just work out the box for JSF 1.x as well.
If you're however still targeting a container of an older Servlet version, then you need to supply a different EL implementation which supports invoking methods with arguments. One of those implementations is JBoss-EL which you can install by just dropping the jboss-el.jar file in /WEB-INF/lib of your webapp and adding the following context parameter to the web.xml. Here's a Mojarra-specific example (Mojarra is the codename of JSF RI):
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
If you're using MyFaces as JSF implementation, you need the following context parameter instead:
<context-param>
<param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
See also:
Invoke direct methods or methods with arguments / variables / parameters in EL

Resources