How to pass argument to method in ui:repeat or c:forEach [duplicate] - jsf

I have just a question in passing parameters on backing beans method.
I would like pass an EL value between a method parameters like:
<p:selectOneMenu id="somsgroup" value="#{store_itemController.filter_sgroup}">
<f:selectItems value="#{commonDataFunctions.getItemByName('store_sgroup', 'id', 'title', '[tb:store_sgroup][fd:title]=${store_itemController.filter_group}', '[tb:store_sgroup][fd:title]', true)}"/>
</p:selectOneMenu>
it seems like ${store_itemController.filter_group} it is not translated because the method receives ${store_itemController.filter_group} just like a string.
Is there a solution?

You can indeed not nest EL expressions this way. EL expressions can only be inlined.
You can use <c:set> to create a new variable wherein the desired expression is inlined in the desired value and then reuse this variable as argument of another EL expression.
xmlns:c="http://java.sun.com/jsp/jstl/core"
...
<c:set var="filterGroup" value="[tb:store_sgroup][fd:title]=#{store_itemController.filter_group}" scope="request" />
...
<f:selectItems value="#{commonDataFunctions.getItemByName('store_sgroup', 'id', 'title', filterGroup, '[tb:store_sgroup][fd:title]', true)}"/>

I would like to suggest to use JBoss EL. If so, you need to configure as below in web.xml.
Download jar file here and reference for previous post.
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>

Related

Setting f:setPropertyActionListener value with a f:param value

I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.

commandLink with ui:repeat in composite component

I am trying to use links in a composite component, my links are in a simple array and do not belong to any managed bean.
<composite:interface>
<composite:attribute name="links" required="true" />
</composite:interface>
<composite:implementation>
<ui:param name="linksSplit" value="#{fn:split(cc.attrs.links, ',')}" />
<ui:repeat var="link" value="#{linksSplit}" >
<h:commandLink value="#{option}" action="#{link}" />
</ui:repeat>
</composite:implementation>
I am getting the following error :
Identity '#{link}' does not reference a MethodExpression instance, returned type: java.lang.String
We are supposed to use String or bean methods in EL expression but I don't understand why we cannot evaluate a parameter which is a String (link in my case).
If I put a real String referenced in my faces-config, it works
<h:commandLink value="#{option}" action="#navigate" />
If you have an explanation or a workaround to get my link working, it would be great
When specifying an EL expression in <h:commandLink action>, it's interpreted as a method expression returning a String (or void if you don't want to navigate). See also the tag documentation:
Name action
Type javax.el.MethodExpression
(signature must match java.lang.Object action())
Description MethodExpression representing the application action to invoke when this component is activated by the user. The expression must evaluate to a public method that takes no parameters, and returns an Object (the toString() of which is called to derive the logical outcome) which is passed to the NavigationHandler for this application.
Given the fact that you seem to want pure page-to-page navigation links, you're actually going in the wrong direction as to using <h:commandLink> for that. You should instead be using <h:link> for that. It generates SEO-friendly and bookmarkable GET links instead of a piece of JavaScript which submits a parent POST form.
<ui:repeat var="link" value="#{linksSplit}" >
<h:link value="#{option}" outcome="#{link}" />
</ui:repeat>
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Note that this all has nothing to do with composite components. You'd have had exactly the same problem when using this in a normal page.

Passing a method to composite component executes the method directly [duplicate]

I have a UI component with a MethodExpression attribute changeListener:
<composite:interface>
<composite:attribute name="changeListener" required="false" method-signature="void actionListener(javax.faces.event.ActionEvent)" />
..
</composite:interface>
<composite:implementation>
<p:remoteCommand name="ajaxOnChange"
update="#{cc.attrs.onChangeUpdate}"
oncomplete="#{cc.attrs.onchange}"
actionListener="#{cc.attrs.changeListener}" />
..
</composite:implementation>
This changeListener attribute is an optional method expression used as actionListener in the remoteCommand and I want to render the <p:remoteCommand> ONLY IF the changeListener attribute has been set.
I have tried several ways to check whether the attribute is set or not, especially:
<c:if test="#{! empty cc.attrs.changeListener}">
and
<p:remoteCommand rendered="#{cc.attrs.changeListener != null}" />
But I get a javax.el.PropertyNotFoundException because it tries to evaluate the attribute as a property instead.
How can I evaluate whether the optional method attribute is set or not ?
thanks
You was in the right direction with <c:if> already. The rendered one is never going to work. You only need to check if the EL expression is been set instead of actually evaluating the whole EL expression as a value expression and checking if its result is not empty, which would of course fail if the EL expression represents a method expression.
<c:if test="#{not empty cc.getValueExpression('changeListener')}">
...
</c:if>
This solution is however somewhat scary: you're grabbing the method expression as a value expression here. However, as long as you don't actually evaluate the enclosed EL expression (like as what your initial #{cc.attrs.changeListener} attempt does under the covers), then there's nothing at matter. There's no other clean way as there's nothing like UIComponent#getMethodExpression() in JSF API.

JSF call message bundle : EL in EL

I am working in JSF2 and I have displayed a resource bundle to display messages from property files.
The configuration seems to be great (if I call #{msg.risk} "toto" is displayed)
messages.properties
...
COMPANYGROWTH=E249
RISK=TOTO
I would like to do this kind of thing :
View
<f:loadBundle basename="toto" var="msg"/>
...
<p:column>
<h:outputText value="#{msg.#{key}}" />
</p:column>
Putting an EL in an EL like #{msg.#{key}} where key would be a declared row value in a datatable. Is there a way to do it ?
Thanks
For that you should be using the brace notation #{bean[property]}.
Thus, so:
<h:outputText value="#{msg[key]}" />
Note that nesting EL expressions is always invalid syntax. You should see #{...} as one big evaluation space where variables interact with each other. You should not see #{...} as a single variable.
See also:
Our EL wiki page

How to call a method with a parameter in JSF

I' ve a JSF page that shows the content of a folder (really it's a dropbox's account content).
I'm using a dataTable to render the content of a ListArray object:
<h:dataTable style="text-align: left" width="600" var="dContent" value="#{backedBean.contents}">
<h:column>
<f:facet name="header">
<f:verbatim>NAME</f:verbatim>
</f:facet>
<h:commandButton value="#{dContent.fileName}" action="#{backedBean.updateContents(dContent)}"/>
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>SIZE</f:verbatim>
</f:facet>
<h:outputText value="#{dContent.size}"/>
</h:column>
</h:dataTable>
But when I run this page I obtain the following error:
/browse.xhtml #34,110 action="#{backedBean.updateContents(dContent)}"
Error Parsing: #{backedBean.updateContents(dContent)} ...
... Caused by: org.apache.el.parser.ParseException: Encountered "
"(" "( "" at line 1, column 28. Was expecting one of:
"}" ...
"." ...
"[" ...
">" ...
"gt" ...
"<" ...
"lt" ...
">=" ...
"ge" ... ... ...
The funny thing is that Netbeans is able to autocomplete the method name so I image that my backend bean is ok. The problem occurs only when I call a method with a parameter.
Any ideas?
Many thanks
Passing method arguments was introduced in EL 2.2. So this is only possible if you're running on a Servlet 3.0 / EL 2.2 capable container like Tomcat 7, Glassfish 3, JBoss AS 6, etc and your web.xml is been declared as per Servlet 3.0 specification.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
>
<!-- Config here -->
</web-app>
If you aren't, then check this answer for alternatives with regard to obtaining current row in datatables, or this answer with regard to replacing the EL implementation by one which supports passing method arguments so that you can use it on Servlet 2.5 / EL 2.1 containers as well.
Jboss Seam can also help to get the feature.
Seam uses JBoss EL which provides an extension to the standard Unified Expression Language (EL). JBoss EL provides a number of enhancements that increase the expressiveness and power of EL expressions.
Example:
pass literal strings using single quotes:
<h:commandLink action="#{printer.println('Hello world!')}" value="Hello"/>
or
for dynamic value
<h:commandButton action="#{hotelBooking.bookHotel(hotel)}" value="Book Hotel"/>
Limitation:
JBoss EL can't currently be used with JSP 2.1 as the compiler rejects expressions with parameters in. So, if you want to use this extension with JSF 1.2, you will need to use Facelets. The extension works correctly with JSP 2.0.
There has actually been a "hack" way of doing this since JSF 1.0. You just create a method on your backing bean that returns a Map, and you can use JSF EL to pass whatever object you want to that method, because JSF thinks that you are passing the key to the map.
Meanwhile, in your backing bean method you actually return an "imposter" map instance that is not really a map at all, whose get() method delegates to the method you wanted to call. In your .xhtml or .jsp file then you can use the square bracket notation to pass the variable.
Extending HashMap is one way to make the imposter map easy to define -- succinct enough to use an anonymous inner class that way.
This is a hack, but it has worked well for me in the past.

Resources