Access flash with h:link in JSF - jsf

When I'm about to navigate to another page, I would like to put an object in the flash. This is how I'm doing it at the moment:
<h:commandLink action="#{bean.foo(object)}">
<h:graphicsImage .../>
</h:commandLink>
And the bean method:
public String foo(Object o) {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("key", o);
return "target.xhtml?faces-redirect=true";
}
I would like to do that with an h:link in xhtml without a bean method (also because I've heard that commandLink navigation is bad). I have something like this in mind, to replace above code:
<h:link outcome="target.xhtml">
<h:graphicsImage .../>
<someTag someAttr="#{facesContext.externalContext.flash.put("key", object)}"/>
</h:link>
Is there such a tag (someTag) that can be used like this?

You can't pass flash attributes like GET attributes with a h:link. ViewParams are not enough? This is the best way to navigate.
But you can put variables to flash scope with c:set. The problem is if you want to set the value dynamically after pressing the link.
Add namespace if not already present xmlns:c="http://java.sun.com/jsp/jstl/core"
<c:set target="#{flash}" property="key" value="object"/>
<h:link outcome="target.xhtml">
<h:graphicsImage .../>
</h:link>

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.

f:param does not work with p:commandLink or h:commandLink on query string

f:param works great with h:link, but not with p:commandLink or h:commandLink.
For example, I have two pages test_first.xhtml and test_second.xhtml, and a backing java bean TestBean.java.
I start running test_first.xhtml.
If I click link1, which is a h:link, the page will redirect to test_second.xhtml. With the help of f:param, the address bar of the browser will show .../test_second.xhtml?id=1. On that page, testBean.userId gets printed.
If I click link2 or link3, the page redirects to test_second.xhtml. However, the address bar only shows .../test_second.xhtml, there is NO ?id=#! And testBean.userId does not get printed on that page.
How can I make commandLink work with f:param? Sometimes I want the link not to redirect to another page but to call some methods of bean depending on the data.
test_first.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form>
<h:link value="link1" outcome="test_second" >
<f:param name="id" value="1"/>
</h:link>
<br/><br/>
<h:commandLink value="link2" action="test_second?faces-redirect=true" >
<f:param name="id" value="2" />
</h:commandLink>
<br/><br/>
<p:commandLink value="link3" action="test_second?faces-redirect=true">
<f:param name="id" value="3" />
</p:commandLink>
<br/><br/>
</h:form>
</h:body>
</html>
test_second.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:viewParam name="id" value="#{testBean.userId}" />
</f:metadata>
<h:head/>
<h:body>
<h:form>
This is the second page.
<h:outputText value="Selected id is #{testBean.userId}" />
<h:commandButton value="Print page id" action="#{testBean.print()}" />
</h:form>
</h:body>
</html>
TestBean.java
#ManagedBean
#SessionScoped
public class TestBean implements Serializable{
private Integer userId;
public void print() {
System.out.println(userId);
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
You misinterpreted the meaning of those two tags, namely <h:link> and <h:commandLink>, therefore, you also misinterpreted the meaning of <f:param> attached to either of the two. In anycase it is worthwhile to always read the documentation before asking the questions to get more insight.
<h:link> renders an HTML "a" anchor element. The value of the component is rendered as the anchor text and the outcome of the component is used to determine the target URL rendered in the "href" attribute. Any child UIParameter components are appended to the String to be output as the value of the "href" attribute as query parameters before rendering...
<h:commandLink> render an HTML "a" anchor element that acts like a form submit button* when clicked ... if the disabled attribute is not present, or its value is false. It renders "#" as the value of the "href" attribute, renders the current value of the component as the link text if it is specified and *renders JavaScript that is functionally equivalent to the following as the value of the "onclick" attribute:
document.forms['CLIENT_ID']['hiddenFieldName'].value='CLIENT_ID';
document.forms['CLIENT_ID']['PARAM1_NAME'].value='PARAM1_VALUE';
document.forms['CLIENT_ID']['PARAM2_NAME'].value='PARAM2_VALUE'; return false;
document.forms['CLIENT_ID'].submit()"
where hiddenFieldName is as described above, CLIENT_ID is the clientId of the UICommand component, PARAM_NAME and PARAM_VALUE are the names and values, respectively, of any nested UIParameter children.
In other words, within <h:link> tag nested <f:param> will end up as a query parameter of the generated URL, while within <h:commandLink> tag nested <f:param> will end up as a request parameter with a given value.
While the first one is clear, the second one deserves a better elaboration. To understand what it does, consider that if we abstract away from the details <h:commandLink> sends a POST request and attaches all nested <f:param> tags as request parameters. But it is up to you how you will handle them, as navigation is entirely in your hands.
So, the first option is to set a hardcoded action attribute, which use case is dubious, like in action="second-page", in which way you didn't pass any query parameter at all. What will be done is POSTing to the same view and forwarding to the second without undertaking any action. Quite a dumb action.
The second option is to specify an action method, like in action="#{bean.action}". In this case you must handle navigation in the provided action method, i.e. return null/void from the method for a postback, or return a navigation case outcome as a string to make a forward to the specified view. As for the request parameters that you passed with <f:param> they will be available with standard JSF means like #ManagedProperty("#{param.name}") on a request-scoped bean, or by calling ExternalContext#getRequestParameterMap() in any-scoped bean, for example, in action method, like in String param = externalContext.getRequestParameterMap().get("name"). So now you have your parameter in action method that you're free to use how you like, just adhere to a set of rules that exist for URLs.
Two things left worth mentioning. Remember that request parameters passed with calling the command link will be available only within that same request, as you might expect it to survive a faces-redirect=true that basically fires another request. The other option is to specify includeviewparams=true to pass through the paramaters of the current view, if that's desired, as mentioned in the other answer.
You could do it by concatenating the parameters with & directly at the action attribute:
<p:commandLink value="link3" action="test_second?faces-redirect=true&id=3"/>
Update 1
You might also consider to add &includeViewParams=true. This way view parameters of your target navigation will be included automatically.

View parameter when navigating to another page

I am using JSF2, and I need to be able to pass a parameter from one JSF page to another via a commandLink.
I am on page funding.xhtml (ViewScoped) and have the following link defined:
<p:commandLink styleClass="toolbar"
action="/application/customerApplicationManagement.jsf">
<p:graphicImage url="/resources/gfx/search.png" />
<h:outputText value="#{msg.menu_searchApplications}" styleClass="toolbarLink" />
</p:commandLink>
I need to pass a string value to the customerApplicationManagement page indicating which page I came from so that after selecting an application, I can return to that page. I have tried several suggestions about how to pass this value including f:param, f:viewParam. I have even tried just adding it directly to the url (?fromPage=funding) etc, but they all seem to work only when the value is passed back to the current page, not a new page I am navigating to.
Can someone show me how this can best be accomplished.
Use <f:param> and <f:viewParam>:
Source page:
<p:commandLink styleClass="toolbar"
action="/application/customerApplicationManagement.jsf">
<p:graphicImage url="/resources/gfx/search.png" />
<h:outputText value="#{msg.menu_searchApplications}" styleClass="toolbarLink" />
<f:param name="fromPage" value="funding.xhtml" />
</p:commandLink>
Destination page (bound):
<f:metadata>
<f:viewParam name="fromPage" value="#{destinationBacking.fromPage}" />
</f:metadata />
<h:link value="Go back!" outcome="#{destinationBacking.fromPage}" />
Destination page (unbound):
<f:metadata>
<f:viewParam name="fromPage" />
</f:metadata />
<h:link value="Go back!" outcome="fromPage" />
Backing bean (only if you want to bind the param):
#ManagedBean
#ViewScoped
public class DestinationBacking{
String fromPage;
public String getFromPage(){
return fromPage;
}
public void setFromPage(String frompage){
fromPage = frompage;
}
}
Your view path will be binded to fromPage property from the destination backing bean and after you can use it to return to the original page.
Also I want to say that this way is a bit 'hackeable' by the end user, I mean, you're passing the original path through pure url. See also other ways to achieve that, as flash scope, which is very useful specially if you're working with #ViewScoped beans.
I don't know the specifics of the methods you tried to achieve your goal and hence we cant tell what was wrong with them, but if we consider your code 'as is' you don't have anything that will pass the string you want.
Not to repeat ourselves, there are plenty of answers here dedicated to using this or that method, so I will give you the best references, in my opinion, of course.
How can I pass a parameter to a commandlink inside a datatable;
ViewParam vs #ManagedProperty;
What can <f:metadata> and <f:viewParam> be used for.
Regarding the usage of back buttons in JSF you could also take a look at my own answer on How to get back to the same page in JSF.
By the way, using POST for page-to-page navigation is considered to be a bad practice. If all you need is to navigate to another page you'd better use plain <h:link> or <h:button> instead.

Resources