Keep url parameters after clicking <h:commandButton> - jsf

I've got a page which takes an id as a url parameter and uses it to get an object and display data about it. On this page we've got a modal which includes a file upload component, so we cannot use ajax to process the save. Instead we do this:
<rich:modalPanel domElementAttachment="parent" id="profilePanel" styleClass="popUp" resizeable="false" moveable="false" autosized="true" zindex="200" top="-10">
<a4j:form enctype="multipart/form-data" id="profilePanelFormId">
<q:box title="Edit Advocacy Profile" width="width6x" wantFocus="true">
<s:div id="profilePanelForm">
<rich:messages rendered="#{messagesUtil.errorsExist}"/>
<a4j:include viewId="/panel/advocacy/advocateProfileEdit.xhtml"/>
</s:div>
<h:commandButton id="cancel" immediate="true" value="Cancel" action="#{advocateManager.cancelEditCommitment}" styleClass="button cancel" tabindex="100"/>
<h:commandButton id="save" value="Save" action="#{advocateManager.saveCommitment}" styleClass="submit" tabindex="101"/>
</q:box>
</a4j:form>
</rich:modalPanel>
We populate the parameter in pages.xml like so:
<page view-id="/advocacy/advocateCommitmentView.xhtml" login-required="true">
<param name="confirmationCode" value="#{advocateManager.commitmentId}"/>
</page>
So far so good. The problem we're running into is when a user clicks save or cancel the url gets rewritten without the necessary id parameter. If the user then refreshes the page it throws errors because it doesn't have this key. Does anyone know how I can call my save method without using ajax and still keep the url parameter or intercept the call and add the parameter back in?

Put ?includeViewParams=true at the end of the action string.

This happens because <h:commandButton/> posts the form, and form posts do not include parameters in the URL. To add the parameters, create a navigation rule that redirects to the same page:
<navigation from-action="#{advocateManager.saveCommitment}">
<rule>
<redirect view-id="/same-page.xhtml" />
</rule>
</navigation>
When doing the redirect, page parameters are encoded and added to the URL. Note that this requires that #{advocateManager.commitmentId} is populated when the redirect is done.

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?

need to open url and pass hidden parameters (post request), primefaces

I am using primefaces. I need to open URL from my UI and pass login credentials and other parameters with that URL. How can I send the request to URL and pass parameters which are not visible. I tried the following:
1)
<p:menuitem value="report" url="http://someUrl" icon="ui-icon-document" ajax="false"
target="_blank" includeViewParams="true">
<f:param id="decorate" name="decorate" value="no" />
</p:menuitem>
2)
<h:outputLink value="http://someUrl" ajax="false" target="_blank" includeViewParams="true">
link
<f:viewParam id="decorate" name="decorate" value="no" />
</h:outputLink>
In these two cases I am trying to pass 'decorate' parameter. It is opening the URL but the parameter is not being passed.
HTML does not allow you to send POST parameters via a hyperlink, which is what an <h:outputLink> renders. You can use a <p:commandLink>, as explained below, to call JavaScript; it should look something like this:
<p:commandLink type="button" onclick="<javascript here>">
Here are two separate ways to achieve this:
Use a normal link to submit a form
JavaScript post request like a form submit

set a parameter in the url via post

I would like to set a parameter in the url via post but this page only perform a method and update the page with h: commandButton.
<h:commandButton value="Simular"
action="#{simulador.simular()}"
style="margin:0 4px 0 0;"
immediate="true">
<f:ajax render="#form" immediate="true"/>
</h:commandButton>
How can I achieve this?
URLs are only changed on synchronous requests. Adding a query string to URL is only possible on GET requests. Sending a redirect after POST is one way to create a synchronous GET request.
public String simular() {
// ...
return "page.xhtml?foo=42&faces-redirect=true";
}
This will redirect to /context/page.xhtml?foo=42.
If you actually don't need to perform any business logic in the action method based on the postback, then you can also just use a normal button instead of a command button.
<h:button value="Simular" outcome="page.xhtml">
<f:param name="foo" value="42" />
</h:button>

Is it possible to forward to Siteminder login.fcc from a JSF action?

I have a "custom" (JSF) login page for my application. My company uses Siteminder for authentication. So, in order to login to Siteminder with a "custom" page, I have to have a form that posts to /login.fcc with the appropriate form fields (username/password and a couple of Siteminder specific hidden fields).
What I am trying to do is to continue to leverage the form validations and such of JSF and still post to login.fcc.
Here is a stripped down version of my custom form:
<rich:messages />
<h:form id="adminLogin" prependId="false">
<h:panelGrid columns="2" styleClass="center">
<h:outputLabel value="HUB USERNAME:" />
<h:inputText id="USER" label="Username" size="12" required="true" />
<h:outputLabel value="HUB PASSWORD:" />
<h:inputSecret id="PASSWORD" label="Password" size="12" required="true" />
<input type="hidden" name="target" value="#{loginController.smTarget}" />
<input type="hidden" name="smagentname" value="#{loginController.smAgentName}" />
</h:panelGrid>
<h:panelGroup layout="block" styleClass="max-width button-panel">
<a4j:commandButton id="adminLoginBtn" value="LOGIN"
styleClass="login-btn"
action="#{loginController.managerLogin}" />
</h:panelGroup>
</h:form>
Note that I have used standard hidden inputs for the target and smagentname fields. This is because I have no need to have both setters and getters in my controller for these fields. I simply want the controller to provide the values when the page renders.
My controller method looks like this:
public void managerLogin()
{
LoginController.LOG.debug("manager is logging in...");
LoginController.LOG.debug("user: " + getRequestParameterValue("USER"));
LoginController.LOG.debug("smagent: " + getRequestParameterValue("smagentname"));
LoginController.LOG.debug("target: " + getRequestParameterValue("target"));
forwardTo(LoginController.SM_LOGIN_FCC);
}
You can see that I am logging the values from all fields except the password field and they all print correctly in my log...so I know I am getting the values. My "forwardTo()" method simply gets the ExternalContext and calls dispatch() on it...passing in the path to the login.fcc page (which is "/forms/login.fcc").
When I input values in the form and click the login button, I see my values in the console but I get a 404 message in my browser.
I can manually put the "/forms/login.fcc" page in the address line and I have no problems with the GET rendering the login.fcc page. But I, of course, don't want to render the login.fcc (GET) I want to peform the Siteminder login (via POST).
It is my understanding that all request parameters are made available through a forward process I was expecting this to work.
I can take this same form and un-JSF-ize it...and make the login button simply submit the form (whose action would be the /forms/login.fcc via POST and it works fine too, but then I loose the benefits of the form/field validations that JSF provides.
Any ideas?
Use the following process:
Follow the SiteMinder redirect
Send your credentials (username/password)
Follow the SiteMinder redirect again
Send the SiteMinder cookies
Here is an article which explains the process in detail:
How to Connect to a SiteMinder Protected Resource

How to create a simple redirect with JSF?

How do I create a simple redirect with jsf?
I tried:
<h:form>
<h:commandButton action="www.google.de" value="go to google" />
</h:form>
But when I click the button, I just stay on the index page. Nothing happens!
What is wrong here?
Is JSF absolutely necessary here? You don't seem to need to submit anything to your side at all. Just use plain HTML.
<form action="http://www.google.de">
<input type="submit" value="Go to Google" />
</form>
Please note that the URL to the external site must include the scheme (the http:// part), otherwise it would just be submitted relative to the current request URI, such as http://example.com/context/www.google.de.
If you really need to submit to your side, e.g. to preprocess and/or log something, then you could use ExternalContext#redirect() in the action method.
<h:form>
<h:commandButton value="Go to Google" action="#{bean.submit}" />
</h:form>
with
public void submit() throws IOException {
// ...
FacesContext.getCurrentInstance().getExternalContext().redirect("http://www.google.de");
}
You can use:
<h:commandButton value="Go to Google" type="button" onclick="window.location.href = 'http://www.google.de';" />
No need for a form.

Resources