JSF: bean scope; session vs request - jsf

I have a managed bean called UserSearchHandler, it has a doSearch method that populates UserSearchHandler.searchResults which are displayed in a table on the userSearch.xhtml page.
I have another managed bean called UserHandler, it has a showUser method and so on.
In the search results table, the user name is a link that, when clicked, is supposed to show user details on a userView.xhtml page. The table and link looks like this:
<p:dataTable var="user" value="#{userSearchHandler.searchResults" >
// ... and so on ... then
<h:commandLink value="#{user.firstName}" action="#{userHandler.showUser}">
<f:setPropertyActionListener target="#{userHandler.userIdToShow}" value="#{profile.id}"/>
</h:commandLink>
Everything works fine when the managed beans are set to session scope.
However, when I change the scope on the beans to request, the search works and the table gets populated, but when I click on the name link nothing happens. I put a break point on the userHandler.showUser method and it never gets hit when the userSearchHandler is set to "request" scope.
Can anyone help explain why this is, or what I'm doing wrong?

That's because the #{userSearchHandler.searchResults} is empty during the new request and therefore JSF is unable to locate the associated row where the commandlink is been invoked in order invoke the action (and to pass/set properties if any).
You need to ensure that the same #{userSearchHandler.searchResults} is precreated during bean's construction/initialization. If it's to be created based on a specific set of parameters, then you've to pass them along with the form as well.
That's exactly the reason why solutions like Tomahawk's <t:saveState /> and new JSF 2.0 view scope exist.
See also:
What are the main disadvantages of JSF 2.0?

I have a couple of ideas. If you're using a in your navigation you can try taking that out. Doing so would mean the browser will not make a new HTTP request when it renders the second window. It is the new HTTP request which clears the request scoped beans by. If that is not an option, you may be able to pass a parameter in your link such as a record id, which could allow you to pull data from your data source matching that id.

Related

JSF Trouble with beans (scope)

So I was testing my JSF application and suddenly I can't pull the value I stored in the bean anymore. I switched from Request scope to Session scope and I was able to pull a value, but it seems to be the value of the last page I clicked.
File structure goes something like this:
About.xhtml sets a page number stored on the Bean and then calls Layout.xhtml which calls Bean.Method() to get Content_About.xhtml to load some text to the page depending on the page number declared in the About.xhtml file.
To my understanding the Request scope should work as long as I don't need to access the stored information past the page loading, but it is acting as if the page number hasn't been set.
With a Session scope declared, it loads the text, but it seems as if it is building the page, then changing the stored value in the bean. It requires that I click on the page I want twice to get the correct information on a page.
Any help appreciated.
Further investigation: I am able to do the following, but it shows the correct page number before and after the method call to load the content.
Page Number: #{MainBean.getPage()}
<h:form>
<ui:include src="#{MainBean.Content()}"></ui:include>
</h:form>
Page Number: #{MainBean.getPage()}
Accepting that the ui is built first, using the default value of the stored variable, I proceeded to set the value in the ui declaration when layout is called.
I had something like:
#{MainBean.setLevel(0)}
#{MainBean.setPage(1)}
<ui:include src="Layout.xhtml"></ui:include>
and changed it to:
<ui:include src="#{MainBean.setLayout(0,1)}"></ui:include>
public String setLayout(int lvl, int pg)
{
setLevel(lvl);
setPage(pg);
return GetPath()+"Layout.xhtml";
}
This allows the bean's variable to be set during the construction of the ui and carry forward through the rest of the request.

jsf get disabled field values in requestscoped bean

Could you please give me some directions on how to pass values from disabled or readonly input fields in xhtml page to requestscoped bean?
I thought that I can bypass jsf checking the field state by disabling
fields in javascipt code on form open and then submit form, but that
did not help too.
I cannot use view scope, because I would have to set then almost
every page in my application in view scope.
It is very inconvenient to use hidden fields for this purpose,
because it would double the number of fields on the page.
Maybe I have missed some clean solution?
Thank you in advance for any help.
Disabling fields using JavaScript didn't work probably because you didn't enable them just before sending a form. Values of disabled fields are not sent (see input documentation).
For example the following code works perfectly well:
<h:form>
<h:inputText id="disabledinput" styleClass="disabled"
value="#{someBean.property}"></h:inputText>
<h:outputScript>
$('.disabled').attr('disabled', 'disabled');
</h:outputScript>
<h:commandButton action="#{someBean.action}"
onclick="$('.disabled').removeAttr('disabled'); return true;"
value="Submit" />
</h:form>
onclick attribute executes JavaScript code that enables input just before sending the form.
If you use AJAX request you have to restore disabled state using oncomplete or similar.
The problem with this solution is that user can manipulate the value. E.g. she/he can use javascript console in a browser to change the input to enabled or use some tool (e.g. curl) to prepare or tamper request. So if the value is sensitive or should never be changed by the user consider storing the value in the session.
IMHO if the value was provided by the user in one of the previous steps then it doesn't matter that much. However, if value is calculated (like total value or something) you should not depend on its value as users could change it. Personally I would prefer to store the value on server side (in session or in flash).

JSF: Bookmarkability with ViewScoped

I am trying to make my app "Bookmarkable", and i am using view parameters to achieve it.
And i think i still do not get the right way to do it right in JSF, even after reading this, and many others.
My problem is that the get parameters get lost after any non-ajax postback, i mean, the parameter value is still set in the bean and the app works correctly, but it gets removed from the URL making the URL invalid.
For instance, having an URL like http://company.com/users?id=4, as soon as that page executes a non-ajax postback (for uploading data, for instance) the URL becomes just http://company.com/users. The app continues to work correctly, but the link is not any more "Bookmarkable".
Is there any way to prevent the non-ajax postbacks removing the viewParams from the URL?
My use case is to be able to bookmark a page to EDIT an object, and there i need to be able to upload data (if not i would not use non-ajax postbacks). I know i would not need any postback if i would want to bookmark the page to only VIEW the data of the object, but that is not my case.
I could also do a redirect to the same page with the same params, and let the app to recreate the view scoped bean, but then i really do not see any benefit over request scoped beans...
Any suggestion is very appreciated.
This behaviour is "by design". The <h:form> generates a HTML <form> element with an action URL without any view parameters. The synchronous POST request just submits to exactly that URL which thus get reflected as-is in browser's address bar. If you intend to keep the view parameters in the URL, while using ajax is not an option, then you basically need to create a custom ViewHandler which has the getActionURL() overridden to include the view parameters. This method is used by <h:form> to generate the action URL.
public String getActionURL(FacesContext context, String viewId) {
String originalActionURL = super.getActionURL(context, viewId);
String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
return newActionURL;
}
Or, as you're based on the comments already using OmniFaces, you could also use its <o:form> component which basically extends the <h:form> with the includeViewParams attribute which works much like the same as in <h:link> and <h:button>.
<o:form includeViewParams="true">
...
</o:form>
This way all <f:viewParam> values will end up in the form action URL.
See also:
Handling view parameters in JSF after post

JSF page navigation failing with NullPointerException

I wrote two pages...one a form where data submitted and second just to confirm the transaction actually carried out some calculation.
I have a managed bean i.e. FormDataBean and a class Reservation.java from which i instantiate for each booking made. Now I have at the end of a form a submit button:
<h:commandButton value="Submit" action="confirmation"/>
in the bean I have setters and getters as usual. in a method i defined I create an instance of Reservation, then set the beans variables to the instance variabels, like
reservation.startDate = startDate;
reservation.endDate = endDate;
reservation.checkRange();
The last method, i.e. checkRange() will use the assigned values to instance variables to carry calculation. it should return a string successful or failure.
Now when I enter data in the form, and press submit, it just refreshes the page but nothing is submitted. because it doesn't go to next page :(
Any idea what is happening? I don't need to define a navigation rule, because in other project, I carry out simple calculation and display result in next page and it worsks! Please advice
Thanks,
Your are missing to tell us some of the more important details so the answer is a kind of guesswork.
As you don't use navigation rules I assume you are using JSF 2, aren't you?
With JSF 2 you can directly set the new navigation target, without navigation rules. A forward to "confirmation" should work if your outcome file is named confirmation.xhtml. Check that. With a navigation rule you could forward it do a different file.
This part should work regardless of the rest.
For the bean not getting any values make sure that you are using the correct scope either through annotation or entry in your faces-config.xml. As you have a quite unusal validation mechanism you probably have to use the session scope.
The correct way would be using an actionlistener that does your checks and then sets the navigation depending on your checks. The bean scope could be more restrictive then.
Did you try action="confirmation?faces-redirect=true"?

Suggest the appropriate method of managing beans in Richfaces

The scenario is like this. I have a rich:tabPanel with about 5 tabs. On first tab there is a rich:datatable. When I click on first column's element (a4j:commandLink), I get another rich:datatable. When I click on first column's element (a4j:commandLink) of this table, I change the tab where I have another rich:datatable and the same thing follows as above. The constraints from previous tab is used to get elements for the current one. If I click on the tab directly I get all elements related to that tab. Each rich:datatable refers to different tables. Each table is interrelated. Each tab refers to a single managed bean. I am using hibernate in backend.
The problem starts now. I dont want the managed beans to be session or application based since there are many variables to store. If I give request scope, the following thing happens. The first table in the tab renders perfectly, however when I click on the first column, the second table doesn't use all constraints since the scope is request, for example actionlistener. What am I supposed to do ?
One thing I can do is define one managed bean for each table. Or forcefully use session scope. Or is there any other way? Please help.
Thanks.
If you are using Richfaces 3.0.0 or above you can annotate your bean with #KeepAlive
or use the tag <a4j:keepAlive beanName="#{bean}" /> instead.
This is an equivalent to the view scope in JSF 2.0.
If you're already on JSF 2.0, use view scope. It's a scope which lives as long as you're interacting with the same page (independently of the browser tab/session!).
If you're still on JSF 1.x, use request scope with an <a4j:keepAlive beanName="#{bean}" /> declared in the view. It behaves like the JSF 2.0 view scope.

Resources