Since Wicket 1.2 RC4, there is a wizard component in wicket-extensions. Examples
of using this can be found in wicket-examples/wizard.
Copied from the mailinglist
There are generally two ways of doing this (I think):
- Page oriented. Create a page for each step, and record your status by either passing it to the step pages as you construct them.
- Panel oriented, using:
- 'replace'. This way you have one panel (e.g. 'mywizPanel'), where your step part of the wizard is in. On a next step, replace the current panel with the next one. The advantage of this is that it is flexible (doesn't matter how many steps you have, you can always replace the panel with an arbitrairy other one. You let Wicket handle back-button support (Wicket will record undo's using a memento like pattern).
- 'set/isVisible'. Here you create all instances of the panels you need beforehand, and put them all on the page (or wizard panel), using different names (e.g. 'myWizStep1' and 'myWizStep2'). The trick here is the set only the one visible that is currently active (thus all others are not rendered). The advantage of this is that you only create the instances once, and that you don't have to record changes for backbutton support. However, it consumes more memory upfront, and you have to know your panel steps beforehand.
With 2, I would record the wizard state with the parent (page or another panel).
Another thing that might be a good idea, is to use command patterns for navigation actions. For example, I use this for a project:
and then have something like:
Anyway, that's just an idea. You might come up with a more elegant pattern, or you might be happy with a tight coupling between the wizard steps.
Building panel-oriented wizard
First, why this way of implementing wizard is better than page-oriented style. When you post to an address1, then redirect to address2 and then display a view, most browsers do not add address2 to history list again and again (save for Opera). Therefore, it is impossible to access old wizard page simply by clicking browser's "Back" button. Also, because all views correspond to one address, it is impossible to navigate directly to a certain wizard page; it is only possible to navigate to the wizard as a whole. This approach simplifies navigation, error handling and makes wizard more robust.
What is a wizard?
A wizard is different from a flow. Flow defines a sequence of states or events, that should take place. Wizard defines a visual component, which helps to build a complex object. Wizard steps allow to cut one big lump of input data into smaller chunks, and to establish dependency of one data block from another.
Using Easy Wizard
note - Easy Wizard is a dead project. The two web pages that had info about it are no longer available. The most recent reference to it was from 2005.
Example: simple two-panel wizard
We will design a simple login wizard, consisting of two panels: Signup panel, where a user enters his login name and password, and Confirmation panel, which redisplays user's name to confirm. Of course, there is no real need to implement login procedure as a wizard, but this is just an example.
Let us start with WizardPanel class. Easy Wizard defines interfaces for state, transition and controller objects, and provides their implementation, that can be reused. We will use standard IWizard and IWizardTransition implementatations, and will reimplement IWizardStep interface in a Wicket panel. This is reasonable because we are building panel-oriented wizard, each panel represents wizard's step and contains data relevant to that step. Therefore, WizardPanel extends Wicket Panel and implements IWizardStep interface. Most of the implementation code is copied from WizardStep class. Now I think that maybe it would be better simply to reuse WizardStep class...
There are two steps/panels: signup and confirm. Signup panel contains a model that it uses to obtain username and password. This approach makes it simple not to accept input data, if the step is not a current wizard step.
In this example each panel contains a form and navigation buttons. These buttons are mapped to wizard events. "Next" button should be immediate as well, because a step should verify first, should it accept input or not. But Wicket does not have explicit method to submit a form (yet?).
WizardPage class is a main page of this sample. It creates wizard controller and steps/panels.
The wizard controller is defined in LoginWizard class. It defines the transition from Signup step to Confirm step:
If validate method of this transition returns true, then wizard moves from signup to confirm step, otherwize it stays on the current step, which is signup step in our case.
Easy Wizard has the option to create error messages when condition of a transition is validated. This example does not use this feature.
Code is available here: http://www.superinterface.com/files/wicket-wizard-src.zip It is not pretty, but it works and shows the concept. Prettifying will follow