I have a page anchors.xhtml which contains a form and an
<h:commandButton action="#{anchorsBean.onRefresh}" value="Refresh" />
which submits to the same page using redirect:
public String onRefresh() {
refresh();
return "anchors?faces-redirect=true";
}
I want to avoid ViewExpiredException on session timeout or caused by other reason. For that purpose I get use of OmniFaces' restorable view handler:
<f:metadata>
<o:enableRestorableView />
</f:metadata>
But surprisingly at this point, in case of expired view, my redirection behavior gets lost: POST request/response simply takes place. Some digging into details reveals me that navigation/redirection is normally triggered by UICommand at Invoke Application phase, however the view root restored by <o:enableRestorableView /> seems to have no children at all. So there's simply no command component to call the default action listener which must handle redirection.
I am using Mojarra 2.1.19 and OmniFaces 1.4.1. I can see in the sources that RestorableViewHandler creates the view but does not build it: can it be the reason for the empty UIViewRoot? Evidently, there's something I am flagrantly missing and misunderstanding...
Most interesting, when I use no <o:enableRestorableView /> but simply remove ViewExpiredException event in my custom exception handler, everything works fine: FacesContext happens to somehow already contain a fully built UIViewRoot (which <o:enableRestorableView />, when included, will later replace with an empty one). So this way I'm getting the originally desired behavior, at least things look like that. But this way is definitely wrong I suppose.
Many thanks in advance for any clarification on this.
Related
I have a sample use case: I have an edit page that use GET parameter "id".
eg. edit?id=1
This edit page is backed by a ViewAccessScoped (CODI) Bean.
In this edit page, I have a datatable with links that link to the same "edit" page, but with another id. (eg. edit?id=2)
<h:link value="#{mecaPart.id}" outcome="edit" target="_blank">
<f:param name="id" value="#{mecaPart.id}" />
</h:link>
The problem, is that the window open correctly, but it is the same bean that is used! And so I am editing the same part...
I have placed a log in #PostConstruct, and it is the same bean reference that is called multiple times. (even with the new ID!)
My question, how can I tell JSF to create a new ViewAccessScoped backing bean when I click the link, and not re-use the actually used one?
Finally, I discovered that #ViewScoped CODI bean did not preserved the backing bean from page refresh. So, I have to use ViewAccessScoped.
According to Gerhard Petracek: http://os890.blogspot.fr/2011/08/scopes-view-scope-vs-view-access-scope.html
the view-scope of jsf2+ is bound to a concrete jsf page. that means: as soon as you navigate to a different page, the state gets lost. that's better than nothing, but not useful for a lot of use-cases. the main use-case which needs it are ajax-requests on a page and the data used by them aren't needed on other pages, but it's pretty easy to break it e.g. with a browser-refresh on a page which stores the data in a view-scoped bean and has no form with input components. (in a previous blog post i described how to use the infrastructure provided by codi to create a session based view-scope to overcome such disadvantages cause by storing view scoped beans as part of the tree-state.)
like with the view-scope view-access-scoped beans are available on a page, but they also exist for the next page. that means: they are forwarded to the next page and get destroyed autom. if they don't get used during the first request of the next page. that's e.g. useful for wizards. if you have a wizard page which doesn't use the bean or you have to support the possibility to interrupt a wizard, you can use the grouped-conversation scope (and even the window-scope) provided by codi. however, due to the powerful api of codi you can also destroy the scope manually at any time (if needed).
So, to solve the problem of opening a new tab with another "ID", I had to set "CODI Client Side WindowHandler", according to the CODI Wiki.
https://cwiki.apache.org/confluence/display/EXTCDI/JSF+WindowHandler
So I added:
<alternatives>
<class>org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.ClientSideWindowHandler</class>
</alternatives>
To the file beans.xml, and I used #ViewAccessScoped. Everything is working smoothly now.
You can use #ViewScoped which also works in CODI
I need a way to manage the creation of the commandlink ID in DataTable, the problem is that when i use it for deleting a record and interrupt the rendering of the page (reloading it by 'ctrl+f5' ) it assigns the same id to another link button, which results in deleting the row containing it.
The problem in question is sound, but the requested solution is not the right one and not easily to achieve in JSF — basically, you'd need to homebrew a custom command link renderer which is designed specifically for usage in data tables and is able to recognize the specific entity.
The right solution is send a redirect to the same view after POST.
public String delete() {
// ...
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true"; // Feel free to hardcode the view ID, though.
}
(if you intend to display some faces message along it, use the flash scope)
A browser refresh would then result in only the redirect being refreshed rather than the POST action.
An alternative is to submit by ajax instead.
<h:commandLink ...>
<f:ajax execute="#form" render="#form" />
</h:commandLink>
A browser refresh would then only re-execute the last synchronous request, which would be the initial GET request which opened the page in question.
I need help. I'm new to JSF and im using JSF2 and richfaces in my project.
I want to clear the form for which I'm using <f:ajax render="#form"/> in refresh button. I have an ADD button on that screen which adds one record and I hit refresh then it's going to the default page. But when I once again go to enter a record then those values which I entered earlier remain in the form fields.
Can anyone please help me out with this issue?
Assuming that you mean the browser's refresh button when you say "I hit refresh", then that can happen if you've incorrectly placed the bean holding view scoped data in the session scope. You're then basically reusing the very same bean as the form is previously been submitted to. Putting the bean in the view scope instead of the session scope should fix this problem. The view scope ends when you navigate to a different page or fires a new request (as by hitting browser's refresh button).
See also:
How to choose the right bean scope?
Update if you're due to bad design restricted to using session scope, then you might want to hack this around by a
<f:event type="preRenderView" listener="#{sessionScopedBeanWhichShouldActuallyBeViewScoped.resetModel}" />
with
public void resetModel() {
if (!FacesContext.getCurrentInstance().isPostback()) {
model = null;
}
}
This will clear the model on every GET request. However, regardless of this hack, you'll still run into serious problems when the enduser opens the same view in a different browser tab/window within the same session.
The right solution is to put the bean in the view scope instead of the session scope, as said earlier.
When I specify process attribute of p:ajax tag, the listener is not executed. If I omit the process attribute, then the listener is called as expected.
Here is the view snippet:
<p:messages id="messages" />
<h:inputText id="inputToProcess" value="#{controller.inputToProcess}" />
<p:selectBooleanCheckbox id="testCheckbox" >
<p:ajax event="change" process="inputToProcess"
update="messages #this inputToUpdate"
listener="#{controller.processChecked}" />
</p:selectBooleanCheckbox>
<h:inputText id="inputToUpdate" value="#{controller.inputToUpdate}" />
And Controller:
#javax.faces.bean.ManagedBean
#javax.faces.bean.ViewScoped
public class Controller implements Serializable {
private String inputToProcess;
private String inputToUpdate;
//getters and setters
public void processChecked(javax.faces.AjaxBehaviorEvent e) {
// doing some stuff here
}
}
I attached a phaseListener to a view with ANY_PHASE PhaseId, and here is what I observed.
When I specify process attribute , the value of the inputToProcess input is successfully set to the controller during the Update Model phase (no exception occurs). Then the Invoke Application and Render Response phases are executed, but no listener is called. One thing I noticed is that checkbox is not set in the end. But, there are no conversion or validation errors, because as I said the Update Model and Invoke Application phases are executed.
If I omit process attribute, here is what I see: the listener is normally called during the Invoke Application phase (since immediate is false by default), and then `Render Response is executed. Checkbox is successfully set.
Is there any explanation for this sort of behavior?
It should work fine at first sight. At least, it works fine that way when using standard JSF components. I'd bet it to be a bug or "feature" of PrimeFaces that it doesn't process the action when the action component is not included in the process. Adding #this to process should solve it. Consider posting an issue report to PrimeFaces guys.
Further, I'd rather use event="valueChange" or event="click" instead of event="change" or just remove the event altogether, it defaults to the right value already (valueChange which will render onclick in checkbox and radio button components). The change event works differently in MSIE for checkboxes and radiobuttons. It's only triggered on 2nd click and forth. You don't want to be browser dependent.
As per your comment:
The problem with the standard JSF checkbox and ajax components, is that the listener is invoked during Process Validations phase, but I need to update the model first!
This is not true. Probably you was using valueChangeListener instead of <f:ajax listener> or confusing the one with the other. The <f:ajax listener> is always invoked during invoke action phase.
I have a Product controller with Index action, which basically creates the view form for post and Index (Post action verb) action on the ProductController which basically save the product to db but when validation errors occur, I am returning a View(mymodel) else when saved, I am returning RedirectToAction("Created,"Product") but for some odd reason when I break into the code , it is hitting the Product Controller action twice rather than just once. Hence the product has 2 records instead of one.
public ActionResult Index()
{
return View()
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
// 2 calls are made to this controller
try
{
// save the product
return RedirectToAction("Created");
}
catch(Exception ex)
{
// recreate the model from form collection
return View(viewData); // when a validation error occurs it comes into the catch block
}
}
Sometimes I have found Firebug to cause this behavior. Try disabling its Script panel, if you have it installed.
Explanation: In some cases Firebug isn't able to get the script sources for the display within its Script panel. In these cases it initiates a second request to get them. See issue 7401 for some discussion about this, which alleviates the problem and is fixed with Firebug 2.0.2.
Here's a basic checklist (copied from here):
Check that you don’t have any image or another elements in the View with an
empty src attribute (<img src=”" /> for example) or have src
attribute referencing something that no longer exists. You better
check directly in the browser's “Page Source”, than in the View itself due to the
possibility of some “dynamic” issues when the View is rendered. Once you
find such empty element in the page's HTML source its usually trivial to
find the same element in your View and fix the issue. This can also happen with <link href="">.
Check that you don’t have any AJAX calls referencing an empty URL (browsers will interpret such empty URL as the current page and will request the current page again making the Controller action execute few times).
You forgot to return “false” from the JavaScript click event handler for a link or button that makes an AJAX call. If you forget to “return false”, the browser simply interprets the default action of the link – regular, non AJAX, calling the same page again)
Sometimes Firebug and YSlow [ Firefox (FF) plugins ] can cause such issues. Just temporarily disable them in FF or test with a different browser.
Watch out for duplicate filters decorating your controller or action. (this was my problem)
Another solution for this case..
I had exactly same problem, running and testing from Chrome. I couldn't debug it because the second call was coming from (external call). I have randomly tested it in Firefox and Internet Explorer where there was no double hit.
Whatever nasty thing it was, I have deleted Chrome cache (everything!!!) and problem has been resolved.
Hope it will help some of you :)
I had a similar issue with a controller action that generated an image, and I was only seeing it with Firefox. There is a really old bug that causes this, that I guess is still there.
https://bugzilla.mozilla.org/show_bug.cgi?id=304574