JSF call message bundle : EL in EL - jsf

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

Related

Passing dynamic param through bundle.properties to alt text value of graphicImage [duplicate]

I have use case in which I have to use resource bundle to display various texts on UI. Some of these resource bundle entries take paramets (e.g. {0}), for these I use h:outputFormat but sometimes that isn't enough.
e.g.
someMessage=Display this message with param {0}
in a resource bundle.
To display it on xhtml I normally do:
<h:outputFormat value="#{msg['someMessage']}"><f:param value="#{someBean.value}"/></h:outputFormat>
That works well when it's a simple case, but for more complex use cases it isn't enough. For example if I want the 'title' attribute of a commandLink to use the above resource bundle entry:
<h:commandLink action="logout" title="#{msg['someMessage']}">
<f:param value="#{someBean.value}" />
<h:graphicImage library="images" name="image.png" />
</h:commandLink>
which doesn't work. I also tried:
<h:commandLink action="logout">
<f:attribute name="title">
<h:outputFormat value="#{msg['someMessage']}"><f:param value="#{someBean.value}"/></h:outputFormat>
</f:attribute>
<h:graphicImage library="images" name="image.png" />
</h:commandLink>
which also doesn't work since f:attibute doesn't allow children.
Even if there is a hack to bypass this (e.g. using hover component from primefaces) there are other fields that might require a parameterized message.
Does anyone know of a way to use MessageFormat that takes an argument in a non-value field of a JSF component?
You could create a custom EL function for this with which you can ultimately end up like:
<h:commandLink ... title="#{my:format(msg['someMessage'], someBean.value)}" />
You can use the MessageFormat API to perform the job, exactly as <h:outputFormat> is doing under the covers.
An alternative is to create a custom component which does the same as JSTL's good 'ol <fmt:message> which supports a var attribute to export the formatted message into the EL scope.
<my:outputFormat ... var="linkTitle">
...
</my:outputFormat>
<h:commandLink ... title="#{linkTitle}" />
Update: JSF utility library OmniFaces has #{of:formatX()} functions and a <o:outputFormat> component for the very purpose.

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.

c:if test eq always returning true

I have to check inserted date and modified date values, which both are string. If they are equal then i wont display edited email or else i will display edited email too. So i have used the below code to validate it.
<b>Created By - </b><h:outputText value="#{o.createdEmail}" /> : <h:outputText value="#{o.createdDateTime}" /><br/>
<c:set var="createdDate" value="#{o.createdDateTime}"/>
<c:set var="modifiedDate" value="#{o.modifiedDateTime}"/>
<c:if test="#{createdDate eq modifiedDate}">
<b>Edited By - </b><h:outputText value="#{o.lastModifiedEmail}" /> : <h:outputText value="#{o.lastModifiedDateTime}" />
</c:if>
Note: o is the variable reference the backend bean.
But it is always displaying it as true even though both values are different. How is this caused and how can I solve it?
Given the way how the code is written (a managed bean with name o makes no utter sense), I do a educated guess that #{o} is declared as var of <h:dataTable> or <ui:repeat>. If that is indeed the case, then that would totally explain the symptoms. JSTL tags runs during view build time, that moment when the JSF component tree is built based on XHTML source code. However, JSF components such as <h:dataTable> and <ui:repeat> runs during view render time, that moment when the JSF component tree needs to produce HTML output.
So, in effects, the #{o} is not available at the moment JSTL <c:if> runs during view build time. You should instead be using a JSF component with rendered attribute which runs during view render time, the same moment as #{o} is been put in the EL variable scope based on current iteration round.
<ui:fragment rendered="#{createdDate eq modifiedDate}">
<b>Edited By - </b><h:outputText value="#{o.lastModifiedEmail}" /> : <h:outputText value="#{o.lastModifiedDateTime}" />
</ui:fragment>
Note: this doesn't affect <c:set>. It merely creates an "alias" to the EL expression, it doesn't immediately evaluate the EL expression, so the <c:set> is completely safe here, albeit somewhat unnecessary as the value doesn't represent such a complex EL expression.
See also:
JSTL in JSF2 Facelets... makes sense?

JSF <h:outputFormat>: use array values as parameters

On my JSF2 page, i'm using internationalized error messages.
In my backing bean, i'm putting the messages into the flash Scope:
flash.put("error", exception.getType());
On the page, this string gets translated this way:
<h:outputText value="#{bundle[flash.error]}"/>
Works fine.
NOW i want to be also able to put (an arbitrary number of) parameters into the message text, that get inserted into the placeholders in the i18n-property in my message.properties. Therefore, i'm putting the parameters as a String array into the Flash Scope, like this:
//exception.getParameters returns String[]
flash.put("errorParams", exception.getParameters())
Now i also want to be able to use this String array as parameters for an outputFormat element, to insert them into a property like Welcome, {0} {1}.
So i tried to achieve this by using ui:repeat:
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<ui:repeat value="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
<!-- also doesn't work: <f:param value="#{_param}"/>-->
</ui:repeat>
</h:outputFormat>
Unfortunately, the param value is ignored and the placeholders of the i18n-property aren't replaced, so the rendered output is Welcome, {0} {1}. When using a "regular" repeater, displaying the array elements just as an outputtext, it works. So the outputFormat tag doesn't seem to support the use of a repeat as a child.
Damn, so close ;) Anyone knows a good way to do what i want, or is there any component library supporting something like that?
The problem here is that ui:repeat is a render-time child of h:outputFormat which it indeed doesn't support at all. You'd like to put multiple f:param elements directly as children of h:outputFormat during build time.
The c:forEach is suitable for this task. The JSTL core tags (which are already included in Facelets, so you don't need to install any extra JARs) do their job during building the view tree, right before it's JSF turn to process/render the view tree.
<html xmlns:c="http://java.sun.com/jsp/jstl/core">
...
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<c:forEach items="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
</c:forEach>
</h:outputFormat>

Resources