Passing a parameter with h:commandButton - jsf

I have a a4j:commandButton which is supposed to redirect me to an appropriate "Edit" page based on an Id, which I wanted to pass as a parameter, something like this:
<h:commandButton action="/details.jsf?faces-redirect=true" value="details">
<f:attribute name="id" value="#{bean.id}" />
</h:commandButton>
The problem is, it doesn't work. I also tried replacing f:attribute with "f:param name="id" value="#{bean.id}" ", but it also failed. The only thing I got to work is an outputLink:
<h:outputLink value="/details.jsf">
link
<f:param name="id" value="#{bean.id}" />
</h:outputLink>
But I'm not really happy with a link, so is there a way to make the commandButton work?
Oh and I also have a bean which is supposed to get that "id" after the redirect:
#PostConstruct
public void init(){
id= resolve("id");
}

Have a look at this article about communication in JSF, by BalusC
f:param only works with h:commandLink and h:outputLink.
You can use an input hidden:
<h:form>
<h:commandButton action="/details.jsf?faces-redirect=true" value="details"/>
<input type="hidden" name="id" value="#{bean.id}" />
</h:form>
And then in your faces-config, I guess is request scoped. If you use the annotations of JSF2, just translate this to the proper annotations.
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>mypackage.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
You need obviously to have getters and setters for that field in the backing bean.
or try to "paint" the link as a button through CSS.

Unless my JSF is extremely rusty, the action attribute on a command button or command link is used to specify the outcome string defined in your faces-config-nav file, or it should point to a method on the bean which will return an outcome (or redirect/whatever).
In your case, if you want to redirect to another page... you should define that in your config file, as a navigation link (with redirect if necessary). Then in your action button you should have something like
<h:commandButton action="showDetails" value="details">
...
<navigation-case>
<from-outcome>showDetails</from-outcome>
<to-view-id>/details.jsf?faces-redirect=true</to-view-id>
</navigation-case>
As an aside, the <f:atribute> tag will work, but it will only set the attribute onto the component. So if you got a hold of the command button in your bean, you could be able to get the attribute value by name. To pass a request param, use the hidden field technique like pakore mentioned

Related

Passing "get" parameters doesn't work, parameter not visible in the link

I'm a beginner to JSF and I want to code a little searchbar on my future website.
I made two pages : index.xhtml and search.xhtml, and I try to pass get parameters from index.xhtml to search.xhtml, so I made this little formular :
<!-- index.xhtml -->
<h:form id="Form_search">
<h:inputText class="search_bar_text" binding="#{se}"></h:inputText>
<h:button class="search_bar_button" outcome="search">
<f:param name="search" value="#{se.value}" />
</h:button>
</h:form>
To summarize, I want to send the content of an inputText to search.xhtml
But there's a problem : when I click on the submit button, no parameters are passed, so instead of having /search.xhtml?search=foobar I only have /search.xhtml.
I also tried this, but this doesn't work either :
<!-- index.xhtml -->
<h:form id="Form_search">
<h:inputText class="search_bar_text" binding="#{se}"></h:inputText>
<h:button class="search_bar_button" outcome="search.xhtml?search=#{se.value}">
</h:button>
</h:form>
Can someone explain to me the reason of this problem and how I can fix it?
The <f:param value> and <h:button outcome> are evaluated during rendering the HTML output, not during "submitting" of the form as you seem to expect. Do note that there's actually no means of a form submit here. If you're capable of reading HTML code, you should see it in the JSF-generated HTML output which you can see via rightclick, View Source in webbrowser.
Fix it to be a true GET form. You don't need a <h:form>, <h:inputText>, nor <h:button> here at all. You don't want a POST form. You don't seem to want to bind the input to a bean property. You don't want a plain navigation button.
<form id="form_search" action="search.xhtml">
<input name="search" class="search_bar_text" />
<input type="submit" class="search_bar_button" />
</form>
Yes, you can just use plain HTML in JSF.
If you really, really need to use JSF components for this purpose for some reason, then you could also use this POST-redirect-GET-with-view-params trick.
First add this to both index.xhtml and search.xhtml:
<f:metadata>
<f:viewParam name="search" value="#{bean.search}" />
</f:metadata>
Then use this form:
<h:form id="form_search">
<h:inputText value="#{bean.search}" styleClass="search_bar_text" />
<h:commandButton styleClass="search_bar_button" action="search?faces-redirect=true&includeViewParams=true" />
</h:form>
This would perhaps make sense if you intend to use JSF validation on it. But even then, this doesn't prevent endusers from manually opening the URL with invalid params. You'd then better add validation to <f:viewParam> itself on search.xhtml.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? (scroll to bottom of answer)
How do I process GET query string URL parameters in backing bean on page load?

Retaining GET request query string parameters on JSF form submit

I have 3 pages:
main.xhtml
agreement.xhtml
generated.xhtml
The agreement.xhtml needs two parameters to load correctly: serviceId and site. So, a normal url looks like this: /app/agreement.xhtml?site=US&serviceId=AABBCC.
I have this button on agreement.xhtml
<h:form>
<h:commandButton value="Generate License File" action="#{agreement.generateMethod}" />
</h:form>
The #RequestScoped bean #{agreement} has this method:
public String generateMethod(){
.......
return "generated";
}
I need that, on click, the generateMethod() method is executed, and after it's done, the user is redirected to the generated.xhtml page. What's happening is that, on click, the page browser sends the user to /app/agreement.xhtml and, since it's not sending the parameters site and serviceId, it crashes.
I tried making the generateMethod() return a "generated?faces-redirect=true", but still nothing. Any ideas?
Your concrete problem is caused because a JSF <h:form> submits by default to the current request URL without any query string. Look closer at the generated HTML output, you'll see
<form action="/app/agreement.xhtml" ...>
You'd thus explicitly need to include those request parameters yourself. There are several ways to solve this. If you weren't sending a redirect, then you could just add them as hidden inputs to the JSF form.
<h:form>
<input type="hidden" name="site" value="#{param.site}" />
<input type="hidden" name="serviceId" value="#{param.serviceId}" />
...
</h:form>
Only, those parameters won't reappear in URL in browser's address bar. This isn't a problem if you're only using using ajax on the same page. The <h:inputHidden> is by the way not suitable as it will confusingly lose its value when a conversion or validation error occurs on the form.
In order to get them to reappear in URL, you need <f:viewParam> and includeViewParams. In order to get includeViewParams to work, you need to declare the following in both the source page agreement.xhtml ...
<f:metadata>
<f:viewParam name="site" value="#{agreement.site}" />
<f:viewParam name="serviceId" value="#{agreement.serviceId}" />
</f:metadata>
... and the target page generated.xhtml:
<f:metadata>
<f:viewParam name="site" value="#{generated.site}" />
<f:viewParam name="serviceId" value="#{generated.serviceId}" />
</f:metadata>
Now you can send a redirect including the view parameters as follows:
public String generateMethod() {
// ...
return "generated?faces-redirect=true&includeViewParams=true";
}
Do note that the bean should be #ViewScoped in order to keep those parameters alive between opening the page with the form and submitting the form, also on validation errors. Otherwise, when sticking to a #RequestScoped bean, you should be retaining them as <f:param> in the command components:
<h:commandButton ...>
<f:param name="site" value="#{generated.site}" />
<f:param name="serviceId" value="#{generated.serviceId}" />
</h:commandButton>
There's no way to set them for <f:ajax> inside input components, your bean should then really be #ViewScoped.
Alternatively, if you happen to use JSF utility library OmniFaces already, then you could also just replace the <h:form> by <o:form> as follows (see also showcase example):
<o:form>
That's basically all. This will generate a <form action> with current query string included.
<form action="/app/agreement.xhtml?site=US&serviceId=AABBCC" ...>
Those request parameters are then just available in the request parameter map of the form submit. You don't need additional metadata/viewparams and you also don't need to send a redirect and your bean can be kept #RequestScoped, if necessary.
public String generateMethod() {
// ...
return "generated";
}
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Your generateMethod would have to return
return "generated?site=US&serviceId=AABBCC&faces-redirect=true";
You can even replace & with & but escape it in your xhtml.
In your generated.xhtml you can catch the parameters that are being passed with <f:viewParam> like this
<f:metadata>
<f:viewParam name="site" value="#{yourBean.site}"/><!--Make sure you have a setter-->
<f:viewParam name="serviceId" value="#{yourBean.serviceId}"/><!--Make sure you have a setter-
</f:metadata>
<h:head>

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.

Binding a JSF bean to a included JSF

I'm at the end of my rope with this one. I'm new to JSF so this is probably my misunderstanding of a lot of stuff.
<ui:composition>
<f:view>
<tr:form>
<ui:fragment rendered="#{param['type'] eq 'myType'}">
<ui:include src="/home/myPage.jspx" />
</ui:fragment>
......
I pass the page a certain type, it display's certain fields/criteria for a form and a bean backs it all because there is a single search.
Within myPage.jspx I have:
action="#{MyBean.submitForm}"
does not work, although a onsubmit="alert('hi');" does work as an attribute of the form element.
I guess what's most confusing is that
valueChangeListener="#{MyBean.stateChanged}"
does work on a field in the myPage.jspx
Why does the action (attribute of a button) not work?
During processing of the form submit, if the button or one of its parent components is not rendered, then the button's action won't be invoked. You need to make sure that the rendered attribute evaluates the same during processing of the form submit as it did when the form was displayed. In your case, you're depending on the value of a request parameter with the name type.
In this particular case, you could solve the problem by retaining the request parameter type by a <f:param> nested in the command button:
<h:commandButton ...>
<f:param name="type" value="#{param.type}" />
</h:commandButton>
Or, if you're using JSF 2.0, placing the bean in the view scope and setting the type parameter in the managed bean by <f:viewParam> can also solve it.
<f:metadata>
<f:viewParam name="type" value="#{bean.type}" />
</f:metadata>
...
<ui:fragment rendered="#{bean.type eq 'myType'}">
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated

cannot set managed-property parameter with a JSF expression value

I have a strange problem which I have been trying to fix for some time but am stuck in one place and don't quite understand what's going on here.
My index page looks like this:
<h:selectOneMenu id="selectMenu" value="#{indexBean.model.selected_id}" styleClass="indexItems">
<f:selectItems value="#{indexBean.myModelValues}" />
<a4j:support event="onchange" reRender="peek" />
</h:selectOneMenu>
<br>
<h:outputText id="peek" value ="#{indexBean.model.selected_id}"/>
<br>
<a4j:commandButton value="Go to Form" action="form" styleClass="indexItems">
<f:param name="selected" value="#{indexBean.model.selected_id}" />
</a4j:commandButton>
The commandButton sends the user to a next page when I want to get the selected position from the selectOneMenu. The problem is that nothing is sent. When I select some value from the Menu the 'peek' outputText is rerendered properly and I can see the correct selection. However it is not sent to the next page and Bean. Surprisingly when I change the value of the parameter to a fixed String it works!!! So i.e. this:
<f:param name="selected" value="someValue1" />
Is read correctly in the next Bean!!! All of the beans are requested scoped with RichFaces #KeepAlive annotation (I tried without the annotation and it's the same). Ihave treied:
-changing a4j:commandButton to h:commandLink or h:outputLink
-changing indexBean.model.selected_id to indexBean.selected_id
-finally changing the input source from h:selectOneMenu to h:inputText
Nothing helps - it is still the same - a hardcoded String is passed correctly to the next page, but when I try to use the expresion the parameter is always empty.
Here I post a snippet of the faces-config.xml:
<managed-bean>
<managed-bean-name>indexBean</managed-bean-name>
<managed-bean-class>id.webapp.beans.IndexBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>model</managed-bean-name>
<managed-bean-class>id.webapp.beans.Model</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>formBean</managed-bean-name>
<managed-bean-class>id.webapp.beans.FormBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>selectedValue</property-name>
<value>#{param.selected}</value>
</managed-property>
</managed-bean>
Does any one have an idea why this doesn't work? I have used the managed-properties parameters like that in the past and it worked (meaning using some dynamically changed values not a static String).
The <f:param> is evaluated during the initial request (when the form is to be displayed), not during the form submit request. So it still remains the initial value, not the changed value.
Give the <a4j:commandButton> an id and refer it in the reRender as well so that its <f:param> get re-evaluated before you press the button.
<h:selectOneMenu id="selectMenu" value="#{indexBean.model.selected_id}" styleClass="indexItems">
<f:selectItems value="#{indexBean.myModelValues}" />
<a4j:support event="onchange" reRender="peek,button" />
</h:selectOneMenu>
<br>
<h:outputText id="peek" value ="#{indexBean.model.selected_id}"/>
<br>
<a4j:commandButton id="button" value="Go to Form" action="form" styleClass="indexItems">
<f:param name="selected" value="#{indexBean.model.selected_id}" />
</a4j:commandButton>

Resources