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

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?

Related

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>

Button as link, <h:button outcome /> not working (no navigation cases used)

I am trying to achieve the following, though with a button.
<h:outputLink value="/admin/category/read">
Cancel
<f:param name="cat" value="" />
<f:param name="subcat" value="" />
</h:outputLink>
I have tried using h:button, though the outcome property does not work since /admin/category/read is not a specified navigation-case.
How to use a button as link, without having to use a navigation-case or server side method?
No, there's no solution using JSF attributes, at least not if you really don't have a navigation case for the h:button.
If possible, I'd advise to use CSS styling as already mentioned in the comments.
But h:button just creates a plain HTML link with onclick="window.location.href=URL". So if you really want, you can build the URL yourself and just use a plain HTML input button like this:
<input type="button" value="Cancel"
onclick="window.location.href='/admin/category/read?cat=&subcat='; return false;" />
Related:
Difference between h:button and h:commandButton
When should I use h:outputLink instead of h:commandLink?

Not A Valid Method Expression in JSF

I have a commandbutton that I want to use to navigate to another jsf facelet, but I am getting a not a valid method expression:
<h:commandButton value="Save Edits" action="editOrDeletePage.xhtml?editing=true;#{product.id};name=#{product.productName};description=#{product.description};quantity=#{product.quantity}"/>
I can get it to work if I only have
action="editOrDeletePage.xhtml?editing=true"
I guess when I have multiple properties that I'm passing, I am not delimiting them correctly. Any ideas?
When the action attribute contains an EL expression, it's interpreted as a method expression. It's thus really only valid when you use action="#{bean.someMethod}". However, your attempt does not represent a valid method expression, it's represents instead a value expression which is not accepted by the action attribute.
If you intend to append additional request/view parameters to the form submit, then you should rather use <f:param>.
<h:commandButton value="Save Edits" action="editOrDeletePage.xhtml">
<f:param name="editing" value="true" />
<f:param name="id" value="#{product.id}" />
<f:param name="name" value="#{product.productName}" />
<f:param name="description" value="#{product.description}" />
<f:param name="quantity" value="#{product.quantity}" />
</h:commandButton>
Note that those parameters don't end up in the request URL (as you see in the browser address bar) and that your theoretical approach also wouldn't have done that, a JSF command button namely generates a HTML <input type="submit"> element which submits to the very same URL as specified in the action attribute of the parent HTML <form method="post">.
Also note that those parameters are not evaluated during the form submit, but during displaying the form. If you intented to pass submitted values along that way, then you're basically doing it wrong. Perhaps you want to specify them as view parameters so that you can use action="editOrDeletePage?faces-redirect=true&includeViewParams=true" as action.
After all, it's hard to propose the right solution for you as you didn't elaborate the concrete functional requirement in detail at all.
If you are using JSF2 you can use h:button for this
<h:button value="press here" outcome="editOrDeletePage">
<f:param name="productId" value="#{product.id}" />
</h:button>

Conditional rendering in JSF [duplicate]

This question already has an answer here:
Ajax update/render does not work on a component which has rendered attribute
(1 answer)
Closed 7 years ago.
Hello I have this code to conditionally render components in my page:
<h:commandButton action="#{Bean.method()}" value="Submit">
<f:ajax execute="something" render="one two" />
</h:commandButton>
<p><h:outputFormat rendered="#{Bean.answer=='one'}" id="one" value="#{messages.one}"/></p>
<p><h:outputFormat rendered="#{Bean.answer=='two'}" id="two" value="#{messages.two}"/></p>
It gets the answer and renders the component but in order to see it on my page, I need to refresh the page. How can I fix this problem? Any suggestions?
The JSF component's rendered attribute is a server-side setting which controls whether JSF should generate the desired HTML or not.
The <f:ajax> tag's render attribute should point to a (relative) client ID of the JSF-generated HTML element which JavaScript can grab by document.getElementById() from HTML DOM tree in order to replace its contents on complete of the ajax request.
However, since you're specifying the client ID of a HTML element which is never rendered by JSF (due to rendered being false), JavaScript can't find it in the HTML DOM tree.
You need to wrap it in a container component which is always rendered and thus always available in the HTML DOM tree.
<h:commandButton action="#{Bean.method()}" value="Submit">
<f:ajax execute="something" render="messages" />
</h:commandButton>
<p>
<h:panelGroup id="messages">
<h:outputFormat rendered="#{Bean.answer=='one'}" value="#{messages.one}"/>
<h:outputFormat rendered="#{Bean.answer=='two'}" value="#{messages.two}"/>
</h:panelGroup>
</p>
Unrelated to the concrete problem, you've there a possible design mistake. Why would you not just create a #{Bean.message} property which you set with the desired message in the action method instead, so that you can just use:
<h:commandButton action="#{Bean.method()}" value="Submit">
<f:ajax execute="something" render="message" />
</h:commandButton>
<p>
<h:outputFormat id="message" value="#{Bean.message}" />
</p>
I know it's not the central point of the question, but as I had this problem many times in the past, I just post it here to help others who are in need.
For those who uses PrimeFaces there's a component in PrimeFaces Extension called Switch.
Sometimes you need to display different outputs or components depending on a value. Usually you can achieve this by using the ui:fragment tag. With the pe:switch util tag you won't have to declare ui:fragment tags, with different checks like ui:fragment rendered="#{!empty someController.value}", anymore.
style="visibility: #{questionchoose.show==false ? 'hidden' : 'visible'}"

JSF 2.0 navigating on commandLink and commandButton doesn't work

I'm using JSF 2.0 and I have a problem with navigation after both commandLink and commandButton. I use following code:
<h:commandLink action="login?faces-redirect=true"
value="#{showElementBean.showElement()}"> Login </h:commandLink>
<h:commandButton action="login?faces-redirect=true" value="Move to login.xhtml" />
These tags are inside a form, login is just an example. Result of clicking on rendered controls is always POST with refresh of a current page. What do I wrong?
Edit:
According to comments of BalusC I' adding real code fragment:
<h:commandLink actionListener="#{showElementBean.showElement(element)}"
value="View" > </h:commandLink>
I have a page with a list of elements and I want to add links that leads to element view page. Thus I need to pass this element to a show page. I'm JSF primer, e.g. in Rails I'd use GET and URL params, but I don't know how to do it 'in JSF-way'.
There are a lot of possible causes for this behaviour. They are all cited in the following answer, along with solutions: commandButton/commandLink/ajax action/listener method not invoked or input value not updated.
However, in your particular case, you seem rather to be interested in plain GET requests instead of POST requests, as all you want is simple page-to-page navigation. In that case, you need a <h:link> or <h:button> instead:
<h:link outcome="login" value="Login" />
<h:button outcome="login" value="Move to login.xhtml" />
(I have no idea what you're trying to do with both #{showElementBean.showElement()} and Login as command link value, so I omitted the former)
See also:
When should I use h:outputLink instead of h:commandLink?
Refer this info: JSF HTML Tags
h:commandButton
The commandButton tag renders an HTML submit button that can be
associated with a backing bean or ActionListener class for event
handling purposes. The display value of the button can also be
obtained from a message bundle to support internationalization (I18N).
Example
<h:commandButton id="button1" value="#{bundle.checkoutLabel}" action="#{shoppingCartBean.checkout}" />
HTML Output
<input id="form:button1" name="form:button1" type="submit" value="Check Out" onclick="someEvent();" />
h:commandLink
The commandLink tag renders an HTML anchor tag that behaves like a
form submit button and that can be associated with a backing bean or
ActionListener class for event handling purposes. The display value of
the link can also be obtained from a message bundle to support
internationalization (I18N).
Example
<h:commandLink id="link1" value="#{bundle.checkoutLabel}" action="#{shoppingCartBean.checkout}" />
HTML Output
Check Out
Noticed that backing bean method is not called if the form is for file upload:
<h:form name="searchForm" enctype="multipart/form-data" method="post" action="/search">
I also faced with that issue and adding the
<h:form><h:commandLink></h:commandLink> </h:form>
solved my problem.

Resources