saving data in between pages - jsf

I have been reading about JSF navigation between pages in an application and I am still a little bit confused. I have a small web application with a series of pages with continue and previous buttons on each page. To save the valid data entered on the view, I am trying to figure out ways to make the valid form data stick when the user goes back and forward. Initially, I had the page views in session scope but I understood that its bad practice. The data that I am capturing can be a managed bean with composite objects within the bean that corresponds to the data that is captured in the pages. But, I read that managed bean in session is not a good idea either. After reading through so many posts, I feel that I should know the solution but its still not very clear as to how to save the validated data into JSF so that it displays when the user navigates back and forth? Appreciate your help.

Seems to me you're trying to accomplish some kind of wizard-like navigation. For this use-case I would suggest the use of a #ConversationScoped backend Bean.
This scope is not provided by the JSF- but by the CDI-framework which just work perfectly together.
To get this to work you essentially have to follow these steps:
Create a CDI Bean like:
#Named
#ConversationScoped
public class MyBean implements Serializable {
#Inject
private Conversation conversation;
...
}
#Named is the CDI alternative to JSFs #ManagedBean.
Your class should implement the Serializable interface to be able to passivate its state.
CDI #Inject the Conversation-object to use in your code.
Start the conversation anywhere inside your code via:
conversation.start();
Do your magic: process input, change data, navigate, persist to db,...
End the conversation (in your case at the last page, maybe after a click on a 'Finish'-Button)
conversation.end();
A quick google search came up with this pretty tutorial implementing a questionaire site which could be useful to you. Have a look at this.
Hope this helps. Have fun!

Are you not persisting the data to a database? If so, you can use a request-scoped managed bean, that way when you navigate back to the original page the updated records will be re-retrieved from the database and your changes will be displayed.

Related

JSF - Appropriate bean scope for keeping data between pages but only "browser tab related"

I am creating a web application using JSF 2.2.20 in which I am implementing a "kinda wizard" flow which lets the user filling input fields and go back and forth the view pages through navigation. I am using a single bean for all these views.
Let's say I have views A.xhtml, B.xhtml, C.xhtml and D.xhtml, all managed by the same bean MyBean.java
I want my application to be "browser tab scoped", which means that
I do not want my bean's data be re-instantiated after every HTTP Request as it happens with #RequestScoped beans or after view changing as it happens with #ViewScoped, I want the data of my bean to be kept between view changes and redirections so the user can go back and forth between pages without losing the data he has already given.
I do not want to use the #SessionScoped scope since each time the user opens a new tab I want the bean to be re-instantiated starting from page "A.xhtml.
Is there any built-in way to achieve the scenario described above using the current JSF version? In case there is not any, could you please propose any workarounds?
Thanks in advance!
I think #ViewScoped is what you are looking for, but it depends on your exact usage.
Couple of notes:
Use javax.faces.view.ViewScoped. Don't use the deprecated managed bean annotation as it works differently.
#ViewScoped works by storing the beans in the view. So each time you load the page you get a view and a viewId that corresponds to that view. So effectively each load of the page (could be read as 'each browser tab') gets its own bean.
#ViewScoped is a passivating scope. That means your beans, and their injected Dependencies, do need to be Serializable.
Use a recent, up-to-date version of your app server, or if you bring in MyFaces manually, use the latest release. I found a number of older versions implementations buggy 5+ years ago, but it seems to work flawlessly now.
If there is a Page Navigation occurring, you probably want to use FlowScoped. This is a multi-page bean that stays alive until you end the 'flow'.
If neither of these two work, you can always implement your own scope which is surprisingly easy with CDI.

Separate Managed bean for a popup dialog

I have three screens(views) associated with separate managed beans for each view.
And, I have a common pop-up dialog which can be opened in all the views.
Can I define a managedbean separately for the pop-up with state #NoneScoped; and maintain an instance of it in each parent bean?? or
Do I need to maintain pop-up data in all three parent views?
Please, suggest me the best practice.
I think this is what you are looking for (check out the answer by BalusC) -
Whats the correct way to create multiple instances of managed beans in JSF 2.0
And since you are using #NoneScoped (unlike #RequestScoped in the above question), I also recommend you to look at this answer by BalusC (about #NoneScoped) -
what is none scope bean and when to use it?
And according to this answer, you can't maintain any instances of a managedbean that is none-scoped, as they are garbaged as soon as they are used.
So, in your case since you have three separate views, for each view, the bean is constructed and used to build the view and garbaged. (Looks like it does not even last for a request cycle). When you request another view, it will be a separate instance.
To have multiple intances of a bean, you can have three properties in a Session-Scoped been (to make them survive across multiple views).
#ManagedBean
#SessionScoped
public class Parent {
private Child child1;
private Child child2;
private Child child3;
// ...
}

JSF passing view parameters by reference - when object must be instantiated

Let's say I've got a register page & a register confirm page. I enter user
details into the register page, navigate to the register confirm page where
I can return back to the register page if there are any mistakes.
I'm going to use view parameters to make the registration data available
from the register page to the confirm page, and vice versa.
Supposing there are 20 items of data to be moving from page to page, that's
a lot of view parameters and a lot of setPropertyActionListeners, especially
as all the data is going to end up nicely packaged in a User object.
So what I want to do is input the data on the register page into the
properties of a User record and send a reference to it to the register
confirm page. What gave me an idea was seeing the BalusC WeakHashMap
converter. This is a JSF converter which has a static weak hash map and
generates a uuid as the value for a map entry and the object reference as
the key. So by specifying this as a converter for f:viewParam you send
the uuid in the query string.
This works fine. The issue I have is that on the register page I have to
get an instance of a User class with new. Then I can do:
<h:inputText value="#{bean.user.firstname}"/>
(etc...), and pass the user instance as a view parameter. It works fine from
the register to the confirm page. The issue is that when I perform the
reverse, sending the user reference back to the register page from the
confirm page I absolutely cannot prevent the register page backing bean
from re-instantiating the user object, after the setter has been called
as a result of the view parameter.
So the converter does it's job and retrieves the User object from the
hash map, calls setUser() in the backing bean, and then I see the
constructor for the User class firing.
I've tried calling new User() from the bean constructor, in #PostConstruct,
in a preRenderView (also checking if an ajax request), but nothing I try
prevents the work of the view parameter from getting wiped out if new is
involved. I'm sure there's a simple solution but I just can't see it right
now.
I'd be grateful for any suggestions for how to solve this problem.
The issue I have is that on the register page I have to get an instance of a User class with new.
So what code is initially creating this new User instance then? If you do this in the preRenderView handler, then you can simply check for null, can't you?
If the view parameter and converter haven't done their job, user would still be null and you create a new instance. The bean constructor and #PostConstruct won't do you any good here, since they both run before the view parameter does its thing, but the preRenderView event is guaranteed to run after it.
#ManagedBean
public class Bean {
private User user;
public void onPreRenderView() {
if (user == null) {
user = new User();
}
}
}
(Something to additionally consider is that the conversation scope already does exactly what you're trying to do here. This is part of CDI not JSF, but if you're running in a Java EE 6 Web Profile compliant AS (JBoss AS 6 or 7, Glassfish V3, Resin 4, ...) you already have it. Otherwise it's just an extra jar.)
After several attempts over more than a year to find a solid long term solution
to this problem, at last! I've found one. The solution comes in the form of the
Apache Myfaces CDI extensions project, aka Myfaces CODI.
This provides additional scopes such as the #ViewAccessScoped which ensures that
if a bean is referenced by a page then it is available for that page. Also
provided is support for conversation groups. In the scenario where I want to
pass an object reference from a register page to a register confirm page, the
confirm page can just access the registerView bean directly on the next request.
Alternatively you can #Inject one bean into another and access it on the next
request, or use f:setPropertyActionListener from the source page.
Myfaces CODI works fine with Mojarra and also with ajaxified component libraries
such as primefaces. The concept is similar to what is provided by Jboss Seam,
though I've found the additional scope support to be better thought out and I've
tested this on glassfish 3.1.1 with no problems.
If you're using #ManagedBean and scope annotations from the javax.faces.bean
package in your code, codi intercepts these annotations and uses it's own
CDI based versions, so you can convert to CDI simply by adding codi as a
dependency to your project and not changing any code.
For me this is like moving from black and white TV to colour TV, I wish I'd
found this stuff sooner.
CODI documentation

CDI/Weld - how to handle browser page refresh after ending conversation?

In the very early days of using CDI I'm navigating to a page with a long running
conversation active using faces-redirect=true, so I have a URL like ..myPage.xhtml?cid=1.
At some point I end the conversation, I mean this has to be a reasonable thing to do
or you might as well use session scope? Anyway, I end the conversation and then the
user hits F5, and then of course this causes a 'conversation not found' error as cid=1
doesn't exist.
Can anyone suggest how to get around this problem? I'm using the Steven Verborgh
ViewScoped implementation and simply using a conversation scoped bean to pass parameters
between pages. So I have for example 2 #ViewScoped beans each of which back page 1 & 2.
I #Inject the #ConversationScoped ParameterBean into both view scoped beans. I start the
conversation (parameterBean.getConversation().begin()) in the action method called from
page 1. In the preRenderView event for page 2 I take a reference to the properties of
the parameterBean into a page 2 backing bean instance variable and end the conversation,
it's done it's job and no longer required.
Except for the F5 problem it works fine. If anyone has any suggestions I'd appreciate it,
hopefully I'm not missing something really obvious. I kind of assuming there's no getting
away from a redirect.
Thanks.
There is no workaround for it. The default #ConversationScoped is utterly broken. I'm using the #ConversationScoped from MyFaces CODI instead. It solves all problems you can get with the standard scope.

How to layout beans for single page design

Hey guys. I'm designing a site that uses the Icefaces framework. I've been reading a book called Real World Java EE patterns. I'm kind of confused how to layout the pages. Normally I would have just a POJO class implement serializable for a bean. This bean would then back each page. With a single page design I'm going to have a bunch of elements on the page. Datatables, trees, inputs, calendars etc. Is it normal or best practice to have separate beans for each datatable, calendar, etc or put that all in one bean? I'm not sure how to approach this. Right now each element is a bean and I'm using the #Inject annotation to have the data table talk to the tree and vise versa. This creates really bad code and if I put this as a member of the class I will get a circular reference because the data table bean has to inject the calendar and the calendar has to inject the data table.
Thanks for any help.
I tend to use a single bean per <h:form> or at least per view (XHTML/JSP file). Any related beans will just be injected in this particular "main" bean (and thus not among each other).

Resources