JSF view parameters and h:form action - jsf

this question is "extending" the following post
Handling view parameters in JSF after post
Asume that I'm creating an custom URL that I'm opening in a dialog.
URL example "test.html?id=123"
I want to insert the "id=123" part into the h:form action so that it returns back to the same view with the extra parameter "id=123" part.
I have followed the above post and worked on the third solution, the custom ViewHandler that extends ViewHandlerWrapper.
I'm modifying the action and the form gets redirected to the same origin (until now it works).
First issue
Lets say I have the following xhtml page.
<f:metadata>
<f:event type="preRenderView" listener="#{bean.init}" />
<f:viewParam name="id" value="#{bean.id}"/>
</f:metadata>
<h:form>
...
...
</h:form>
When i post the above i get the correct id value on the back end.
If i resubmit the post i get null values, the url however stays the same (test.html?id=xxx)
Cant figure out why i'm getting null values on the second submit
Second issue is that when I have validated the form and everything is fine, my submit method returns back a new url "test.html?force-redirect=true..." but this does not happen, instead the URL is the same as the one entered in the h:form action, (if i make a custom redirect with the new URL then it works and i get redirected to "test.html?faces-redirect=true...").
My question, I guess is a theoretical one, is this the supposed behavior?
Thanks,
Dimman

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.

Get url parameter into facelets view after user session timeout

I am building a CRUD web application using JSF. I have a problem with loading a page after the user session has timed out. That is i lose the parameters I need to construct the view (even though the parameters are still visible in the url like so: 'someurl/view.xhtml?pid=5'.
In the .xhtml file the parameter pid is used to load some content from an underlying database when constructing the view. When the user has been inactive for a while their session times out, and if they try to reload the page in the browser they are forwarded to the login page (the 'someurl/view.xhtml?pid=5' still intact) and on succesful login go back to the view.xhtml page where I wan't the view to be constructed as if their session had never timedout.
However this does not happen because the 'pid' parameter is no longer set in the view. But since the 'pid' parameter is still visible in the url I feel like I should be able to get it into the view and load the protein with this id from the database.
These are the things I've tried:
#{protein.setProteinById(param.pid)}
and
#{protein.setProteinById(param['pid'])}
and
#{protein.setProteinById(request.getParameter('pid'))}
and
<c:set value="${request.getParameter('pid')}" var="pid" />
#{protein.setProteinById(pid)}
Is this possible to do? Then how?
I'm no expert, but wouldn't you set it in the managed bean?
As far as I know there are two methods for doing this.
One method is using in your facelet to push a view parameter back into a bean (I have a scenario where this doesn't work because of other things, so have no experience with it)
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
I have a prerender method, which is always called before a render
<f:metadata>
<f:event type="preRenderView" listener="#{MyController.prerenderMethod}" />
</f:metadata>
And inside the method, I look at the parameters:
public void prerender(ComponentSystemEvent event) {
value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
}

data exchange using view scoped bean

Trying to wrap my head around using view scoped beans. Please forgive the length of my posting.
I have a view: page1.xhtml which uses a bean and a commandButton that submits the form, invokes a method of that same bean via the action attribute.
The return value of the method causes a navigation rule to 'navigate' to page2.xhtml. So it is my understanding that the bean named "player" used by page1.xhtml goes out of scope once navigation takes the request flow to page2.xhtml. After all, each view uses a view scoped bean named "player". I need to convey a parameter named id. So page1.xhtml has a element as a child element of the commandButton used to 'submit' page1'.
Page2.xhtml uses the following construct as I want the view scoped bean to be loaded prior to the rendering of page2.xhtml:
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{player.id}" />
<!-- this should cause bean to be loaded before it's needed for initial rendering -->
<f:event type="preRenderView" listener="#{player.initFromId}"/>
</f:metadata>
</ui:define>
In the player.initFromId method, I dump out to stdout the keys & values of the map returned by FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
What do I see? [I chopped most of the client saved view state off from this listing :-)]
most of the keys are fully qualified UI component names, named with the component hierarchy naming as expected. Good. Typical POST nv pairs...
Finally my question: am I correct in assuming the key: id is there because of the f:param element as the child of the commandButton caused the commandButton's impl code to push the key+value into the request parameter map? I hope so but I don't like assuming too much. Almost always gets me deeper into trouble.
But the f:viewParam doesn't result in the player.setId() method being invoked prior to player.initFromId() - via the preRenderView event. player.initFromId() is invoked but not the setter??
I hope my assumption is right as I can't imagine it being a design goal to make use of the UI component field names by the code invoked by a different view/page (in this example, page2.xhtml). That would tightly couple the implementation of each page, making the externalized navigation rules practically pointless. I am also assuming that a goal of using the f:viewParam and f:param is to provide minimal coupling (only at the declarative level - page1 declares it provides a param, page2 declares a need for the param - protocol is left to the framework).
Player.initFromId - key:id, value:37
Player.initFromId - key:javax.faces.ViewState, value:H4sIAAAAAA[....]YQfAAA=
Player.initFromId - key:javax.faces.partial.ajax, value:true
Player.initFromId - key:javax.faces.partial.execute, value:#all
Player.initFromId - key:javax.faces.partial.render, value:registrationForm:regPage
Player.initFromId - key:javax.faces.source, value:registrationForm:SubmitButton
Player.initFromId - key:registrationForm, value:registrationForm
Player.initFromId - key:registrationForm:SubmitButton, value:registrationForm:SubmitButton
Player.initFromId - key:registrationForm:firstName, value:Bob
Player.initFromId - key:registrationForm:j_idt18:carriers, value:Sprint
Player.initFromId - key:registrationForm:j_idt18:city, value:Sparta-test4
Player.initFromId - key:registrationForm:j_idt18:dob_input, value:
[ many other UI components key+value pairs omitted]
from page1.xhtml:
<p:commandButton tabindex="0" id="SubmitButton" value="Register"
action="#{player.register}" update="regPage" >
<!-- this needs to be set after the register() method completes. is that so? -->
<f:param name="id" value="#{player.id}"/>
</p:commandButton>
Many thanks for taking the time to read this excessive posting.
You seem to be navigating by a forward. A forward basically creates a new view during render response phase. The <f:viewParam> doesn't run on a forwarded request. It runs on the initial request only (as originally fired by the client). You need to navigate by a redirect instead of a forward so that the client will be instructed to fire a brand new GET request, triggering all the <f:viewParam> works. You can achieve that by adding faces-redirect=true parameter to the navigation outcome like so:
return "page2?faces-redirect=true";
This however loses all request parameters of the current request. So you'd need to explicitly add it to the navigation outcome:
return "page2?faces-redirect=true&id=" + id;

Difference between h:button and h:commandButton

In JSF 2, what is the difference between h:button and h:commandButton ?
<h:button>
The <h:button> generates a HTML <input type="button">. The generated element uses JavaScript to navigate to the page given by the attribute outcome, using a HTTP GET request.
E.g.
<h:button value="GET button" outcome="otherpage" />
will generate
<input type="button" onclick="window.location.href='/contextpath/otherpage.xhtml'; return false;" value="GET button" />
Even though this ends up in a (bookmarkable) URL change in the browser address bar, this is not SEO-friendly. Searchbots won't follow the URL in the onclick. You'd better use a <h:outputLink> or <h:link> if SEO is important on the given URL. You could if necessary throw in some CSS on the generated HTML <a> element to make it to look like a button.
Do note that while you can put an EL expression referring a method in outcome attribute as below,
<h:button value="GET button" outcome="#{bean.getOutcome()}" />
it will not be invoked when you click the button. Instead, it is already invoked when the page containing the button is rendered for the sole purpose to obtain the navigation outcome to be embedded in the generated onclick code. If you ever attempted to use the action method syntax as in outcome="#{bean.action}", you would already be hinted by this mistake/misconception by facing a javax.el.ELException: Could not find property actionMethod in class com.example.Bean.
If you intend to invoke a method as result of a POST request, use <h:commandButton> instead, see below. Or if you intend to invoke a method as result of a GET request, head to Invoke JSF managed bean action on page load or if you also have GET request parameters via <f:param>, How do I process GET query string URL parameters in backing bean on page load?
<h:commandButton>
The <h:commandButton> generates a HTML <input type="submit"> button which submits by default the parent <h:form> using HTTP POST method and invokes the actions attached to action, actionListener and/or <f:ajax listener>, if any. The <h:form> is required.
E.g.
<h:form id="form">
<h:commandButton id="button" value="POST button" action="otherpage" />
</h:form>
will generate
<form id="form" name="form" method="post" action="/contextpath/currentpage.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="form" value="form" />
<input type="submit" name="form:button" value="POST button" />
<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="...." autocomplete="off" />
</form>
Note that it thus submits to the current page (the form action URL will show up in the browser address bar). It will afterwards forward to the target page, without any change in the URL in the browser address bar. You could add ?faces-redirect=true parameter to the outcome value to trigger a redirect after POST (as per the Post-Redirect-Get pattern) so that the target URL becomes bookmarkable.
The <h:commandButton> is usually exclusively used to submit a POST form, not to perform page-to-page navigation. Normally, the action points to some business action, such as saving the form data in DB, which returns a String outcome.
<h:commandButton ... action="#{bean.save}" />
with
public String save() {
// ...
return "otherpage";
}
Returning null or void will bring you back to the same view. Returning an empty string also, but it would recreate any view scoped bean. These days, with modern JSF2 and <f:ajax>, more than often actions just return to the same view (thus, null or void) wherein the results are conditionally rendered by ajax.
public void save() {
// ...
}
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
When should I use h:outputLink instead of h:commandLink?
Differences between action and actionListener
h:button - clicking on a h:button issues a bookmarkable GET request.
h:commandbutton - Instead of a get request, h:commandbutton issues a POST request which sends the form data back to the server.
h:commandButton must be enclosed in a h:form and has the two ways of navigation i.e. static by setting the action attribute and dynamic by setting the actionListener attribute hence it is more advanced as follows:
<h:form>
<h:commandButton action="page.xhtml" value="cmdButton"/>
</h:form>
this code generates the follwing html:
<form id="j_idt7" name="j_idt7" method="post" action="/jsf/faces/index.xhtml" enctype="application/x-www-form-urlencoded">
whereas the h:button is simpler and just used for static or rule based navigation as follows
<h:button outcome="page.xhtml" value="button"/>
the generated html is
<title>Facelet Title</title></head><body><input type="button" onclick="window.location.href='/jsf/faces/page.xhtml'; return false;" value="button" />
This is taken from the book - The Complete Reference by Ed Burns & Chris Schalk
h:commandButton vs h:button
What’s the difference between h:commandButton|h:commandLink and
h:button|h:link ?
The latter two components were introduced in 2.0 to enable bookmarkable
JSF pages, when used in concert with the View Parameters feature.
There are 3 main differences between h:button|h:link and
h:commandButton|h:commandLink.
First, h:button|h:link causes the browser to issue an HTTP GET
request, while h:commandButton|h:commandLink does a form POST. This
means that any components in the page that have values entered by the
user, such as text fields, checkboxes, etc., will not automatically
be submitted to the server when using h:button|h:link. To cause
values to be submitted with h:button|h:link, extra action has to be
taken, using the “View Parameters” feature.
The second main difference between the two kinds of components is that
h:button|h:link has an outcome attribute to describe where to go next
while h:commandButton|h:commandLink uses an action attribute for this
purpose. This is because the former does not result in an ActionEvent
in the event system, while the latter does.
Finally, and most important to the complete understanding of this
feature, the h:button|h:link components cause the navigation system to
be asked to derive the outcome during the rendering of the page, and
the answer to this question is encoded in the markup of the page. In
contrast, the h:commandButton|h:commandLink components cause the
navigation system to be asked to derive the outcome on the POSTBACK
from the page. This is a difference in timing. Rendering always
happens before POSTBACK.
Here is what the JSF javadocs have to say about the commandButton action attribute:
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.
It would be illuminating to me if anyone can explain what that has to do with any of the answers on this page. It seems pretty clear that action refers to some page's filename and not a method.

Use GET request for form submission in JSF 2.0

Is there a way to submit a form and have the URL include the parameters, that is submit as a GET request.. rather than POST?
form.jsf/?firstName=John&lastName=Doe
I thought would work (instead of the normal , however it doesn't seem to grab the form data.. any ideas?
yes you can with preRenderViewEvent
you can have something like this in view
<f:metadata>
<f:viewParam name="team" value="#{teamEditView.team}"/>
</f:metadata>
<f:event type="preRenderView" listener="#{teamEditView.setupEditPage}"/>
where you can pas view params and invoke the listener and fetch data acording to params in that listener method.
You can change the action of the form to be get instead of post. This will add the form values to the qs instead of posting them.
Replace <h:form> by <form> and use either #ManagedProperty in the model side or <f:viewParam> in the view side to set those parameters as bean properties.

Resources