Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What scope to use in JSF 2.0 for Wizard pattern?

Tags:

jsf-2

I have a multi-page form, aka a Wizard pattern, where Page 1 corresponds to Step 1 of the wizard form, Page 2 corresponds to Step 2, etc. Each page other than the last has a Next button on it that takes you to the next page in the form. The final page has a submit button that submits all the data for all pages in the wizard.

What scope should I use to maintain the state of the data entered on each form? e.g. should I use a View Scoped bean that holds all the data entered on all pages? Will that work since I'll be navigating to different pages (Which I believe are considered to be different "views"; and if they're different views, I believe the View Scoped data will be lost when you navigate to the next page in the wizard)

like image 667
BestPractices Avatar asked Mar 27 '12 20:03

BestPractices


1 Answers

I believe the View Scoped data will be lost when you navigate to the next page in the wizard)

That's correct. The view scope lives as long as you're interacting with the same view and get trashed whenever a new view get created. You're looking for the "conversation scope". This isn't available by any of the JSF managed bean scopes. This is however available by CDI @ConversationScoped. So if your environment happen to support CDI, you could make use of it:

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named
@ConversationScoped
public class Wizard implements Serializable {

    @Inject
    private Conversation conversation;

    @PostConstruct
    public void init() {
        conversation.begin();
    }

    public void submitFirstStep() {
        // ...
    }

    // ...

    public String submitLastStep() {
        // ...

        conversation.end();
        return "someOtherPage?faces-redirect=true";
    }

    // ...
}

The conversation is managed by the automatically inserted cid request parameter.

If you'd like to stick to the JSF view scope, then your best bet is to create a single page wherein you render the multiple steps conditionally:

<h:panelGroup rendered="#{wizard.step == 1}">
   <ui:include src="/WEB-INF/wizard/step1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 2}">
   <ui:include src="/WEB-INF/wizard/step2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 3}">
   <ui:include src="/WEB-INF/wizard/step3.xhtml" />
</h:panelGroup>

Or, you could use a 3rd party component library like PrimeFaces which has a <p:wizard> component for exactly this purpose.

like image 87
BalusC Avatar answered Oct 07 '22 20:10

BalusC