Why does returning empty string from action method not recreate view? - jsf

I have a JSF page with a form that contains multiple textfields (p:inputtext) and a submit button. The page is backed by a ViewScoped backing bean. When the submit button is hit, an action method is called that returns an empty String ("").
According to this answer of BalusC, returning an empty string will refresh the view and recreate the ViewScoped backing bean.
However, when I submit my filled out form, the reloaded page still retains all my text input. How is this possible? Shouldn't the form be empty since the backing bean and view have been recreated?

#dmatob is right. When you have a JSF page backed by a ViewScoped bean:
If the method returns null, the bean won't be recreated (the values stay the same) but the page is reloaded.
If the method returns the same or another page, the bean will be recreated (it resets the values) and the page is reloaded.
I was facing the same few hours ago: trying to reset the values when the method is successfully executed. So after reading around and around, I found something that finally worked out:
You have to use action instead of actionListener (Differences here)
<p:commandButton value="Save" action="#{backingBean.save()}" />
So the method must return a String
public String save(){
if(validations==true){
return "currentpage.xhtml?faces-redirect=true";
}
return null;
}
When everything is okay, it will recreate the bean, refresh the page and reset the values. Otherwise the method returns null so it will refresh the page but the bean.
[EDITED]
If the method is returning null or empty String, the bean isn't recreated: the PostConstruct (init event) isn't being triggered, so that means the values stay the same. On the other case, if it returns a String (redirecting to some page), the init event is called so the values are initialized.
The JSF page is reloaded in both cases: when returning null/empty String or not.
Hope it helps you... Let me know ;-)

In a view scoped bean, only when your action method returns null, the bean doesn't initialize again.
If you want the action method to go back to the submitted form and reload the bean, your method must return the name of the page that contains the form.

Related

How to restore ViewScoped bean when user clicks back button?

Lets say I have a #ViewScoped Bean behind my current page A. Now the user navigates to page B via a normal get request, lets say to www.google.com.
When the user clicks the back button of the browser, I would like to restore the #ViewScope of the previous page, so that it appears exactly as it was left. Is that possible to achieve somehow?
I dont want to make my page A #SessionScoped so that the backing beans do not disturb each others state when opened in two browser tabs.
Since version 2.6 OmniFaces has this feature, is called #ViewScoped(saveInViewState = true) But with some caution!
It's very important that you understand that this setting has potentially a major impact in the size of the JSF view state, certainly when the view scoped bean instance holds "too much" data, such as a collection of entities for a data table, and that such beans will in fact never expire as they are stored entirely in the javax.faces.ViewState hidden input field in the HTML page. Moreover, the #PreDestroy annotated method on such bean will explicitly never be invoked, even not on an unload as it's quite possible to save or cache the page source and re-execute it at a (much) later moment.
A more programmatical solution is the #ConversationScoped. With the convertsation id as parameter can you restore the view.
conversationscope example
Yes it is possible, pass parameter like this using f:param this will pass your parameter to the next screen.
<h:commandLink action="screenName" value="#{search.participantName}">
<f:param value="#{searchcus.participantId}" name="PARTICIPANT_ID"/>
<f:param name="PARENT_SCREEN_CODE" value="SEARCH_PARTICIPANT"/>
</h:commandLink>
After that in init() method get value as a parameter to fetch the result.

jsf navigation to another method

I am developing an application using jsf 2.0 and i have the following situation:
I have 2 managed beans.
On the first managed bean i have a method that process some data and then store the result in session.After the data was stored in session i need to invoke a method on the second bean that will display the information from session.
The problem is that if i return a string from the first bean method that correspond to the seconds bean method view the data is not processed, and of course not displayed.
What i need is some navigation rule that from the first bean would redirect me to the second bean method, and the second bean method would return a string with the corresponding view name.
update
maybe a
<f:event listener="#{secondBean.methodToBeInvoked}" type="preRenderView" />
would help me achieve that.
Is this the right approach ?

further continuing of double press

In a previous question BalusC gave me good advice on how a button, in place of a commandButton is useful for non ajax navigation. In particular it updates the destination address in the http: position which is useful for the user to bookmark a page.
I tried to use this information to my advantage until I came upon a problem. In a button I tried to use outcome="#{backing.something}" to find out that it gives me a null result. This looks like a timing problem in that action="#{}" is evaluated only when the button is pressed whereas outcome apparently wants a fixed string which gets checked when the page is loaded.
So I went back to commandButton with ajax="false". This has a problem that my navigation address is the page I came from, not the one I am navigating to. This is the wrong bookmark for the user.
I appreciate all the help I have received in stackoverflow on my learning exercise.
Ilan
The <h/p:button outcome> is not intented to invoke a bean action method, but to contain the outcome string directly. Any EL in there is evaluated immediately as a value expression. So the method behind it would immediately be invoked when you just open the page containing the <h/p:button>.
There are in your particular case basically two ways to invoke a bean action method on navigation. If you need to invoke it before the navigation takes place and the action isn't intented to be re-invoked everytime when the enduser reopens/reloads the GET request, then make it a POST-Redirect-GET request. It's a matter of adding faces-redirect=true to the outcome value in query string syntax.
E.g.
<p:commandButton action="#{bean.submit}" ... />
with
public String submit() {
// ...
return "nextpage?faces-redirect=true";
}
This way the browser will be redirected to the target page after POST, hence the enduser will see the target URL being reflected in the address bar.
Or if you need to invoke the action everytime when the enduser reopens/reloads the GET request, do the job in the (post)constructor or preRenderView listener method of the request/view scoped backing bean instead.
E.g.
<p:button outcome="nextpage" ... />
with
#ManagedBean
#RequestScoped
public class NextpageBacking {
public NextpageBacking() {
// In constructor.
}
#PostConstruct
public void onPostConstruct() {
// Or in postconstructor (will be invoked after construction AND injection).
}
public void onPreRenderView() {
// Or before rendering the view (will be invoked after all view params are set).
}
// ...
}
The pre render view listener method needs to be definied as follows in the nextpage
<f:event type="preRenderView" listener="#{nextpageBacking.onPreRenderView}" />
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters

Reset JSF Backing Bean(View or Session Scope)

I want to reset by JSF backing bean when some method is invoked. Assume that there is a command button, someone press it and after succesfull transaction, my View or Session scope JSF bean should be reseted. Is there a way to do that?
Thank
I found the solution for View scope.
public static void removeViewScopedBean(String beanName)
{
FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(beanName);
}
A view scoped bean will be recreated when you return non-null or non-void from the action method, even if it would go back to the same view. So, just return a String from the action method, even if it's just an empty string:
public String submit() {
// ...
return "";
}
To make it complete, you could consider sending a redirect by appending the ?faces-redirect=true query string to the returned outcome.
public String submit() {
// ...
return "viewId?faces-redirect=true";
}
A session scoped bean is in first place the wrong scope for whatever you're currently trying to achieve. The bean in question should have been be a view scoped one. Ignoring that, you could just recreate the model in the action method, or very maybe invalidate the session altogether (which would only also destroy all other view and session scoped beans, not sure if that is what you're after though).
just clear all views:
FacesContext.getCurrentInstance().getViewRoot().getViewMap().clear();
and remember to implements Serializable in all views
You could also refresh the page from javascript, so the ViewScoped Bean will be reseted, for example in a primefaces commandButton:
<p:commandButton value="Button" action="#{bean.someAction()}" oncomplete="location.reload()"/>
I solve the problem with code like this:
((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getSession().removeAttribute("bean name");
By this way I enter to session scoped bean and reset it without the data that was there before

Managed Bean property value not rendered during Render Response Phase

I am not able to figure out what I am doing wrong. Request your inputs. Please.
I have a request scoped managed bean , which has a List of which I render as a datatable in my JSF 1.2 Apache my faces application. When I submit the form , and since there are some server side validations that fails, I add a FacesMessage and show the same JSF page.
In this request-response cycle , In the INVOKE-APPLICATION Phase , I am able to see the values of the List of but the when the page is rendered with the FacesMessage, the datatable is empty.
The other bean-properties and their values are retained in this request-response cycle except for this List / Datatable.
This is how the datatable is constructed in the action method - initial request
if(getInputXMLString() != null
&& getInputXMLString().length() >0)
{
List<NodeDetailsVO> nodes = Utility.inputXMLStringNodeDetailsVO(getInputXMLString());
setSelectedNodes(nodes);
}
When I try the same as above in the postback request (inside the other action method),It works okay.When I add my business Logic inside a private method, and If I call it above this code or after this, It doesn't work.I am only using the getter of the List in the private method. And in the getter method - I only have sysouts inside if and else.
This is how the datatable is rendered in the xhtml page:
<h:dataTable width="80%" cellspacing="0" border="1"
id="nodes_datatable" cellpadding="2"
style="border-collapse:collapse;"
value="#{createBean.selectedNodes}"
binding="#{createBean.selectedNodesHTMLDataTable}"
var="aResult"
columnClasses="columnAlignRight,columnAlignLeft"
>
This is not the normal case. I do see only two possible causes:
The datamodel (the List as you calls it) is been reset somehow. Probably the getter method is doing more than only returning the datamodel and has reloaded it, but some requestbased parameter/condition is missing.
The datatable or one of its parent components has a rendered attribute which evaluated false.

Resources