Set bean property from JSF page - jsf

I need to do very simple thing - pass current URL from JSF (2.0) page to the managed bean. This is needed to get URL of the login form which will redirect user back to the current page after login. (I use GAE and the bean is the wrapping around its user service, if it does matter). Any obvious way I tried doesn't work
<c:set /> - doesn't work (w/o any error or warning message)
getter which takes current URL as a parameter - doesn't work.
So many questions and many recipes, but all are complex and not elegant. Why? May be I (as other who asking) missed a key design principle? I'll appreciate any answer - simple and straightforward recipe or explanation why not to do so.

It's available by #{request.requestURL} (or if you only want the domain-relative path, use #{request.requestURI}). Use f:param to pass it and #ManagedProperty to handle it.
<h:commandButton action="#{bean.submit}" value="submit">
<f:param name="url" value="#{request.requestURL}" />
</h:commandButton>
with
#ManagedProperty("#{param.url}")
private String url;
Noted should be that f:param inside a h:commandButton doesn't work in JSF 1.x. You'd like to use h:commandLink instead.
Update as per the comments: I understood that you wanted to "pass current URL to the managed bean". But you actually want to "access current URL in managed bean".
In that case, either replace #{param.url} by #{request.requestURL}:
#ManagedProperty("#{request.requestURL}")
private String url;
Or obtain the raw HttpServletRequest instance from under the JSF hoods by ExternalContext#getRequest():
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
String requestURL = request.getRequestURL();

Related

JSF passing parameter to session bean in url

I'm a JSF beginner and I have an easy JSF question but I couldn't solve the logic here.
I open new mv.xhtml page via commandbutton like this:
<p:commandButton value="#{grBean.protocolName(item)}"
onclick="window.open('/SearchMap/faces/mv.xhtml?url=#{item}')">
</p:commandButton>
And I have mvBean which is a session scope. I get the url parameter with a function which is called in postconstructed init method. The method is like:
Map <String, String>tempMap= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
if(tempMap.get("url") !=null)
url=tempMap.get("url");
The problem is here, as mvBean is session scoped, the init method is called only once so I can't get a new url parameter naturally.
I want to use mvBean as a sessionScoped coz I want to keep all the passing urls in an ArrayList.
So, how can I get the url parameter when I use session bean? Or do you have any suggestion or solution?
Thanks for help.
You don't have to do it in init(), here is a quick solution. Put this on your mv.xtml page, somewhere inside <h:form>
<p:remoteCommand name="onload" action="#{mvBean.checkUrl()}" autoRun="true" />
and move your logic from init() to public void checkUrl().

How to pass objects from one page to another page in JSF without writing a converter

first of all sorry for my english. I have two pages in JSF2, one to list Passengers and another one to create/update passengers. I have also two #ViewScoped beans, one with the list of passengers and one for hold in pageB the selected passenger. I see the ways to pass the passenger through viewParam or #ManagedProperty but i don´t want to write a converter.
What i want to know if there is a way to pass the object from pageA to pageB without passing the id of the passenger and write a converter or without passing the id and then go to the DB to retrieve the passenger.
What i do and works is the following. I set in flash scope through setPropertyActionListener the selected object and navigate to pageB, in the #PostConstruct of the viewScopedBean i get the flashScope and retrieve the object. As i said, this works but i don´t know if it is correct. Here is the code
Page A:
<p:column width="10" style="text-align: center;">
<p:commandButton icon="ui-icon-pencil" action="editClientes?faces-redirect=true">
<f:setPropertyActionListener target="#{flash.pax}" value="#{row}"/>
</p:commandButton>
</p:column>
#PostConstruct of pageB bean
#PostConstruct
private void initBean(){
this.pax = (Passenger) JSFUtils.getFlashScope().get("pax");
if(this.pax == null){
this.pax = new Passenger();
}
}
Is this correct, or the correct way is to write a converter?
Thanks.
Depends on whether you want the /editClientes request to be idempotent ("bookmarkable") or not.
The flash approach is not idempotent. It's not possible to link/share/bookmark the /editClientes URL in order to edit a specific client. When the enduser copies this URL for sharing/bookmarking and re-executes the request on it (even though it's just pressing [enter] in browser's address bar), all the enduser would face is an empty edit form for a new client instead of the one the enduser initially selected via flash scope.
The request parameter approach is idempotent. The enduser is able to get exactly the same response everytime the enduser re-executes the request.
It's not our decision whether your /editClientes page should be idempotent or not. It's yours.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)

Choosing how to pass parameters to a target bean/page using JSF

I have been using JSF for a few years now, but I still have doubts when it comes to deciding how to pass parameters to a target page/bean.
I do think this question is a bit complex, and that some may tell me to break it down into smaller questions. But, I also think that the answer to all of the questions bellow are related, and that it addresses the lack of intuitiveness when all you want JSF to do is: "Go to that page and pass this as a parameter".
First, how to decide between Forward and Redirect?
After that, how to choose between h:commandLink/h:commandButton, h:link or h:outputLink?
Then, combined with the option I choose above, should I use f:param or f:setPropertyActionListener? Will both properly pass parameters to the target bean, independently of its scope?
Finally, on the target bean/page, when should I use f:viewParam, or recover parameters from the request programmatically?
I'm going to answer your questions based on my own experience. Some of them are so open that more than one answer could fit.
A page forward is the way to go unless you explicitly require the browser url to be changed. A page forward is basically faster than a redirection as it requires less steps. A page redirect is required if you want to make your views bookmarkable.
Use <h:commandLink />/<h:commandButton /> only when you need to POST the server. Later on, you'll be able to perform a page forward or a redirection depending on what the method returns. As an example:
<h:commandLink action="#{bean.processForm}" value="Submit" />
public String processForm(){
try{
save();
return "list";
}
catch(Excepcion e){
addFacesMessage("Error saving");
//Error saving the object, keep in the same view
return null;
}
}
Use <h:link outcome="list" value="Go to list" /> for pure page to page navigation within the JSF application. You can use either page forward and redirect. Use <f:param /> to pass view parameters.
<h:outputLink value="www.stackoverflow.com" /> could be used for external links to other sites (not into your application). Use <f:param /> to pass view parameters. I however prefer to use plain HTML with <a href="www.stackoverflow.com" /> myself for this case.
As for passing parameters to action methods in POST requests, you've got several options. f:setPropertyActionListener was so popular in JSF 1.x, but if you're already at 2.x I would recommend you going with EL 2.2, which allows method parameter declaration. Being able to use it depends on the application server you're using, but even if not available you could import yourself. Then, you'll be able to do things like that:
<h:commandButton action="#{bean.saveCar(currentCar)}" value="Save Car" />
Use it wherever you can, it'll make things just easier.
For the view parameters, use <f:viewParam /> too. It's the standard JSF way of parsing the parameters from the GET request, so just let the framework do the retrieving work for you!
See also:
JSF 2 link, commandLink and outputLink example
Using EL 2.2 with Tomcat 6.0.24
What is the difference between redirect and navigation/forward and when to use what?

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");
}

JSF and richfaces: h:commandlink in richfaces table not working properly

When using h:commandlink(or commandbutton) inside a rich:dataTable, the action specified is never invoked, neither is the corresponding managed bean instantiated(whether it is at request or session scope)...
instead, the same request is performed.. (page reloads)..
have seen what appeared to be similar issue on forums, but is not actually the problem i am having..
the h:commandlink /button work ok outside of the rich:datatable..
Does anyone have any advice?
here is a code snippet:
<h:commandLink id="commLink" actionListener="#{hBean.test}" action="#{hBean.viewTranslation}">
<h:outputText value="#{trans.translationName}"/>
</h:commandLink>
</rich:column>
The bean is apparently request scoped and the datamodel is not been loaded during bean's construction (at least, during apply request values phase of the subsequent request). You need to preserve the same datamodel for the subsequent request, else JSF cannot locate the row item associated with the clicked link. The most straightforward way is to load the datamodel in the bean's constructor or #PostConstruct method.
A quick fix/test is to put bean in session scope. The datamodel will then be saved in the session scope and be available in the subsequent request. But this has more impact on user experience (e.g. unexpected results when having the same page opened in different browser windows/tabs in the same session). If you're already on JSF 2.0 (which is likely not the case since you're using RichFaces), then the new view scope would have been the solution.
Related questions:
h:commandLink is not been invoked - contains an overview of all possible causes of this behaviour.
If you are using RichFaces 3.0.0 through 3.3.3, use the tag a4j:keepAlive. It will works even with request scope.

Resources