h:link with includeViewParams=true does not always include viewparams - jsf

For some reason,the does not always append the view parameters to the produced link. I can't figure out why. If I change the outcome to another similar link,then it is processed correctly.
Can anyone point me to some requirement that could not be fulfilled? I didn't find anything relevant in the docs.
I am trying to set up 4 views backed by a single bean. Those views all contains the same view parameters, but only one of them process them. All view use the same template.
So i have in all views
<f:metadata>
<f:viewParam name="param1"
value="#{bean.param1}"/>
<f:viewParam name="param2"
value="#{bean.param2}"/>
</f:metadata>
<ui:composition template="/onpage/template.xhtml">
// ...
And in one of them, i included a <f:viewAction>
In the template I have some links
<h:link outcome="#{bean.outcome1}"
value="Go to view1"/>
<h:link outcome="#{bean.outcome2}"
value="Go to view2"/>
and in the bean:
private String param1; // And get/setters
private String param2; // and get/setters
public String getOutcome1() {
return "/my/path.jsf?some=param&includeViewParams=true";
}
public String getOutcome2() {
return "/my/path2.jsf?some=param2&includeViewParams=true";
}
With this setup, some of the links point to "/my/path.jsf?param1=value1&param2=value2" as expected, while others point to "/my/path2.jsf?some=param2" for no apparent reason, and without any information in the log.
All this running on glassfish 4/JSF 2.2/primefaces 4.
THanks

Answer part of the OP comments:
What happened is that I mixed XML namespace domains. The pages using xmlns:f="java.sun.com/jsf/core were working correctly, while those using xmlns:f="xmlns.jcp.org/jsf/core were not. See The metadata component needs to be nested within a f:metadata tag. Suggestion: enclose the necessary components within <f:metadata> for more details.
Note: JSF 2.2 schemas use the xmlns:f="xmlns.jcp.org/jsf/core namespace.

Related

Bean's method that returns to the previous page

After performing the appropriate action, the method of my bean must ensure that the browser back to the previous page. How can I handle it?
I am using the CDI Conversation.
Pass the current URI as request parameter along during navigation to the page containing that action.
<h:link value="Go to page containing that action" outcome="pageContainingThatAction.xhtml">
<f:param name="from" value="#{request.requestURI}" />
</h:link>
(use #{view.viewId} instead if you want to pass the view ID)
Set and remember that parameter representing the URI in the view/conversation scoped managed bean.
<f:metadata>
<f:viewParam name="from" value="#{bean.from}" />
</f:metadata>
Finally redirect to that URI in that action method.
public void thatActionMethod() throws IOException {
// ...
externalContext.redirect(from);
}
After asking you a couple of question in comments, I think what you want to do is :
On your button, specify the attribute action to a function in your bean that return a String.
The String returned need to be the navigation path to the page you want to be redirected.
If the validation is wrong on button click, then simply return null and it will stay on same page.
Make sure you define the proper navigation rule in faces-config.xml
See this tutorial for how to configure navigation rules.
See Primefaces commandButton doc for info on action tag.

Referencing ui:params with hyphens in the name

After many years of avoiding JSF, I'm finally diving in but having problems doing the simplest of things. In the JSTL world, it's easy to reference things with hyphens in the name by doing ${requestScope['big-bad-invalid-name']}. However, that doesn't seem to work with a <ui:param> (or I'm simply starting with the wrong object--the likely issue).
I have a simple file that's referencing a template:
<html xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<ui:composition template="/WEB-INF/template/main.xhtml">
<ui:param name="require-data-main" value="/something" />
<ui:define name="content">...</ui:define>
</ui:composition>
</html>
Sadly I can't figure out how to reference my param since #{require-data-main} is going to freak out due to the hyphens. I've tried #{param['require-data-main']}, #{viewScope['require-data-main']}, #{pageScope['require-data-main']}, #{applicationScope['require-data-main']}. My param doesn't seem to exist anywhere.
Update #1 -- I created another param without hyphens (camel case). Nothing managed to resolve the value as I've tried above. A plain #{requireDataMain} did, however. I have a large number of JSPs already written. So I'm not too keen on changing my variable names. I'd still love to find out how to reference the param with the hyphens in the name.
Has anybody seen my param? Is there an alternate way to retrieve the param?
A JSF page should use Managed Bean to access your java code. If you have a controller class for your jsf page, you could inject it to jsf using EL: #{managedbean.field} where managedbean is a following class:
#ManagedBean(name = "managedbean")
public class YourBean {
private String field;
//getter and setter for field
}
Hope that I understood your problem correctly.

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.

View parameters in different beans

I've got a page called trip.xhtml where I take parameters out of the URL using the following code:
<f:metadata>
<f:viewParam name="tripid" value="#{tripBean.tripId}" />
<f:viewParam name="seats" value="#{tripBean.seats}" />
<f:event type="preRenderView" listener="#{tripBean.processParams}" />
</f:metadata>
The TripBean looks like this (simplified):
#ManagedBean
#RequestScoped
public class TripBean implements Serializable {
private static final long serialVersionUID = -4885781058258859229L;
private Long tripId;
private int seats;
// Getters and setters for tripId and seats
On the bottom of the trip.xhtml page I have a h:link:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
What I expect is that the URL I get when I click this link is something like "/customer/booking.jsf?tripid=2&seats=1". This is only the case when I put the following code on my booking.xhtml page:
<f:metadata>
<f:viewParam name="tripid" value="#{tripBean.tripId}" />
<f:viewParam name="seats" value="#{tripBean.seats}" />
</f:metadata>
Although what I actually want is to use another bean. Changing the code to:
<f:metadata>
<f:viewParam name="tripid" value="#{bookingBean.tripId}" />
<f:viewParam name="seats" value="#{bookingBean.seats}" />
</f:metadata>
The BookingBean also has 2 properties tripId and seats which are identical to the TripBean, but when I try to click the link now, I only see a seats-parameter which is set to 0. ("/customer/booking.jsf?seats=0")
Does anyone have any idea why I can't seem to pass the viewparams to the other page when I'm trying to use another bean to store them in? And IF it is impossible to store it in another bean, how can I put those values from TripBean in BookingBean?
Quick work-around I used:
Not using includeViewParams="true" , but adding parameters to the link manually (see below) "fixes" the problem. Although I'm still wondering why it won't work with includeViewParams!
<h:link outcome="/customer/booking.xhtml" value="#{msg['page.trip.booking']}">
<f:param name="tripid" value="#{tripBean.tripId}" />
<f:param name="seats" value="#{tripBean.seats}" />
</h:link>
f:viewParam works exactly like h:inputText. This means that it uses the same expression as a source (when rendering) and as a target (when updating the model). If you had:
<h:inputText value="#{a.test}" />
You would never ask "how to make the inputText read from b.foo and write to a.test", yet everyone seems to expect such behavior from f:viewParam.
Anyway, there is a simple answer. To append any values to link, you just need to use f:param:
<h:link outcome="/customer/booking.xhtml" value="Book this trip" >
<f:param name="tripid" value="#{bookingBean.tripId}" />
<f:param name="seats" value="#{bookingBean.seats}" />
</h:link>
The link content corresponding to the following tag:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
is generated during the render-response phase of the request for the trip.xhtml view. If you need the URL to contain the view parameter values, then you must provide these values in the URL used to access the view, or you must set these values in the model, before the render-response phase is complete. If you do not perform either of these, the generated hyperlink will contain the default values for the view parameters.
In simpler words, you must:
either ensure that the trip.xhtml view is accessed with the necessary parameters: trip.xhtml?tripid=x&seats=y, especially if the view is to be accessed with parameters at all times.
or you must set the values in a method that gets executed before the link is rendered by the JSF runtime. The constructor of the BookingBean class or a #PostConstruct annotated method in the class would be ideal places to set the values. You could also reset/update the values of the bean in other methods of your managed bean, in the event of actions being performed in the view. Note, that JSF runtime will invoke getTripId and getSeats to include the values of the view parameters tripId and seats in the resulting URL, so you ought to verify the behavior of these methods as well.
Your question on why you are unable to specify bookingBean in the EL expression for booking.xhtml, instead requiring you to specify the supposedly unexpected value of tripBean is due to the fact that the includeViewParams attribute of the link tag, will include the parameters of the to-view and not the from-view. Simply put, the JSF runtime will invoke bookingBean.getTripId() and bookingBean.getSeats() and not tripBean.getTripId() and tripBean.getSeats().
While this might seem counter-intuitive, you ought to understand that the JSF specification treats this scenario quite differently. In most interactions performed by a user, the action URL of a component is generated when the user performs the action and not until then. The link tag on the other hand, requires preemptive computation of the URL, and hence the JSF runtime treats this quite differently as "pre-emptive navigation". When the URL is being constructed, the objects pertaining to the view parameters of the target view must be accessible, in order for the URL to be meaningful. The reason for the values being 0 in the URL, is that a new BookingBean instance is created during this evaluation and the default values are being used instead. You can quite obviously avoid this by using the TripBean instead (and most examples of includeViewParams demonstrate this), or you can set values during the construction of the BookingBean object.

Resources