Is the JSF 2.0 View Scope "back button" safe? e.g. if I store a model in View Scope and go from page 1, page 2, page 3, to page 4, modifying the model object along the way (via input fields), and then hit the back button twice to go back to page 2 and make changes (taking me again to page 3), will the model in view scope have only changes that were made when page 2 was originally rendered or will it have later pages' changes?
Oracle ADF had/has something called "process scope" that handles this by tokenizing what is placed into session, so each page has its own copy of the model.
To start, the view scope is bound to a particular page/view. Multiple views won't share the same view scoped bean. The view scope starts with an initial GET request and stops when a POST action navigates with a non-null return value.
There are in general the following scenarios, depending on whether the browser is instructed to cache the page or not and the JSF state saving configuration. I'll assume that the navigation between those pages took place by a POST request (as it sounds much like the "Wizard" scenario).
When the back button is pressed:
If browser is instructed to save the page in cache, then browser will load the page from the cache. All previously entered input values will reappear from the browser cache (thus not from the view scoped bean in the server side!). The behavior when you perform a POST request on this page depends further on the javax.faces.STATE_SAVING_METHOD configuration setting:
If set to server (default), then a ViewExpiredException will occur, because the view state is trashed at the server side right after POST navigation from one to other page.
If set to client, then it will just work, because the entire view state is contained in a hidden input field of the form.
Or, if browser is instructed to not save the page in cache, then browser will display a browser-default "Page expired" error page. Only when the POST-redirect-GET pattern was applied for navigation, then the browser will send a brand new GET request on the same URL as the redirect URL. All previously entered input values will by default get cleared out (because the view scoped bean is recreated), but if the browser has "autocomplete" turned on (configureable at browser level), then it will possibly autofill the inputs. This is disableable by adding autocomplete="off" attribute to the input components. When you perform a POST request on this page, it will just work regardless of the JSF state saving method.
It's easier to perform the "Wizard" scenario on a single view which contains conditionally rendered steps and offer a back button on the wizard section itself.
See also:
javax.faces.application.ViewExpiredException: View could not be restored
What scope to use in JSF 2.0 for Wizard pattern?
Related
Background
I have a view page(abc.html.haml) with 2 drop down options A and B. A, B are lists which hold a set of records whose parts I am showcasing through the UI.
By default on hitting the controller#index action(called via browser url), the page populates with the records from the A list.
I then have an Ajax call which populates the same page with the records from list B, on choosing the drop down menu. Let's assume I have now moved from State A to B using the drop down option.
Issue
Once, I have the page populated with records from list B, Now, upon page refresh, My drop down menu still holds the same state 'B', but the default set of records which load from the controller#action on page refresh is from the list A(thus the state of the drop down menu should be 'A').
Any inputs on how I can get a work around for this ?
Thanks.
I am not sure if I understand your problem completely, but a few options I can think of:
Use javascript to change the URL when selections are made in the drop downs. You could add paramaters to the URL that could reflect the state of the drop downs, you could then parse these on load of the page.
Give the user a refresh button that you control, then you can send information back to the controller on refresh so that you load the right defaults.
Store the current users selections in the database via ajax calls as the user makes them. I don't know the context of your app, so I don't know how feasible this is. Then you could obviously load these on page load if they exist.
The simplest option however would be to reset all controls on page refresh, I think users expect that behaviour anyway.
I am new to struts2. I am working on the struts2 with spring application.
I developed user registration functionality. In this registration process have the 3 steps(3forms). First page is step1 contains some fields, second page is step2 contain some other fields and step3 contains some other fields.I used session map in the action class to put the all field values of all forms.After submission form in step3 it goes to call rest service and give the response.If the response is OK then i am redirecting to success page step4. In some cases if user is already exits then it gives response existed user then am redirecting to step5 page. In this page i used one message " Sorry the user is already exists" and with one link "Home Page".
I used this link <s:a id="next" href="/sample/register/user.action"> Homepage </s:a> in step5 page. After clicking on this link it goes to homepage(means step1 page) fine,but it doesn't contain user entered values. I have to maintain all field values in the step1,step2,step3 process. How to achieve this problem.
Please any one can give suggestion.
IF you are using session map to persist values being entered by the user, i believe they should be available in the session until you have not removed them from the session or session expired.more over when you do redirect a new request -response cycle started by the framework and a new value stack will be created that means all old values will be lost.
From your description i believe you are creating a wizard like functionality and if this is the case i believe struts2 provide a more elegant and flexible solution
ScopeInterceptor
This is designed to solve a few simple issues related to wizard-like functionality in Struts
Still you need to show how you trying to show the values in the form being filled by the user if something fails or when user is already exists in the system as described in your case.In this case you need to fetch object/data from the session.
I've been searching for a way to remove the initial page container after jQuery mobile loaded the next page content via $.mobile.changePage(...)
What I'm experiencing is that this initial DIV element, created when the page is first shown will always remain on the page - and will only be hidden after calling $.mobile.changePage(...)
I need this initial page container to be removed instead, since some old data reside there that should be reset on first page change.
Anyone has a solution? Been searching the web for it but to no avail.
I have also tried to do $('#first-page').remove() after I called $.mobile.changePage(...), but that will remove the initial page and make the new loaded page hidden!
EDIT: solved by clearing up the initial DIV using .html("")
You could just make next page load without ajax, this should remove the initial page.
data-ajax="false"
Hope this helps!
I take it that you are dynamically creating these pages. There is a hidden method in the API, but you can apply it to any page and then upon that page's exit, it will be removed.
$.mobile._bindPageRemove
So, it might look like this
newpage.attr( "data-" + $.mobile.ns + "external-page", true ).one( 'pagecreate', $.mobile._bindPageRemove );
NOTE: Since this is a hidden method, it is part of the hidden API and could be subject to change without notice upon upgrade. Test carefully upon upgrade if you use this.
I did:
$.mobile.changePage('login.html', {changeHash:false});
changeHash (default: true) Type: Boolean Decides if the hash in the
location bar should be updated. This has the effect of creating a new
browser history entry. It also means that, if set to false, the
incoming page will replace the current page in the browser history, so
the page from which the user is navigating away will not be reachable
via the browser's "Back" button.
I need to show, or hide a search component in my JSF2 application based on the page the user is on. I'm trying to do this by setting a "fromPage" attribute into the session, for example like this:
session.setAttribute("fromPage", "aboutUs");
These attributes are being set whenever the user clicks on a link in the homepage, and I check for them while serving the site's pages. It works well when I use h:commandLinks.
But when I change to h:link this stops working because apparently all the "outcome" methods of h:links on a page are getting called when the page is rendered, and so the "fromPage" attribute always represents the last "outcome" method called -- and it's useless for my purpose.
So, is there any other way to know which page is the user clicking to? And which page am I on?
Use UIViewRoot#getViewId() to learn which view is currently been opened. The current UIViewRoot is available by the implicit EL variable #{view}.
<p>Hi user, you're on #{view.viewId}.</p>
<h:panelGroup rendered="#{view.viewId == '/aboutUs.xhtml'}">
<p>This will be rendered when the current view is aboutUs.xhtml.</p>
</h:panelGroup>
Has anyone had to deal with multiple AntiForgeryTokens on a child view of a master page? The scenario I am thinking about is as follows:
The view contains a Form with an AntiForgeryToken rendered as a hidden field.
The view is contained by a master page that has another AJAX submitted form.
The issue here is that I need to encapsulate the hidden field in the Form and at the same time, I need to render another token for submission on the AJAX submitted form in the master page. I can't make any assumptions that a token will be rendered in the child page since the child page may not have a form on it.
My first thought would be to render a single global AntiForgeryToken for the entire page that all posts used, but then the forms would not post the token as the hidden input field would be located outside of the form.
Thanks for any advice!
It should be possible to render an Html.AntiForgeryToken() separately within each form. The runtime is designed with this scenario in mind. The first call to AntiForgeryToken() sets a flag saying "I've set the token, any other calls to me for this request should use the same token value."