7

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)

BestPractices
  • 12,738
  • 29
  • 96
  • 140
  • I think that ViewScope works properly only with Ajax. But I would recommend this option. – Gaim Mar 27 '12 at 20:18

3 Answers3

13

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.

Erwan Leroux
  • 108
  • 2
  • 11
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I unfortunately do not have access to a CDI container. I guess I will likely then go with p:wizard or the conditional rendering. Would using JSF 2.0's "Custom Scope" facilities provide another alternative? – BestPractices Mar 27 '12 at 21:06
  • Yes, it should surely be possible with a custom JSF2 scope. It's only not going to be some trivial code which I could type off top of head (just because I never tried like that :) ). – BalusC Mar 27 '12 at 21:09
  • @BalusC How to make proper facelet composition with it ? It resulted in double include for me.. one from the page with this panelGroups.. and other from the particular step page.. right now both the steps and panelGroups pages, have ui:composition tags and i guess thats the problem.. When i try to remove ui:composition tag from step page, get xhtml error. I checked other topics here, but they always show only this panelGroup fragment, not whole html page code, so that i can see what im missing.. and couldnt find one example with complete page. – 10101101 Mar 28 '20 at 13:24
0

You can find an example using the conversation scope for creating a wizard at this site:

JEE6 – CDI and Conversation Scope

0

From my pov, good choice here is session scoped beans. When needed, user will be able to interrupt the wizard, visit other pages, doc, manuals, whatever, and get back to the same wizard step. Of course it can be done via view-scoped beans (see BalusC answer). Personally I prefer view-scoped beans when ajax is heavily involved. In that case I'd recommend to combine these two scopes.

andbi
  • 4,426
  • 5
  • 45
  • 70
  • I wouldn't recommend the session scope for this. This will result in irregularities when having the wizard page open in multiple browser windows/tabs. – BalusC Mar 27 '12 at 20:40
  • @BestPractices, sure, it depends. There are cases when ALT-F4 is also a problem, you cant win everywhere )) – andbi Mar 27 '12 at 21:15