Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Excerpt
hiddentrue

How to build a wizard in Wicket

Panel
borderStylesolid
titleTable of contents
Table of Contents
minLevel1

Note

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):

...

Another thing that might be a good idea, is to use command patterns for navigation actions. For example, I use this for a project:


  public interface INavigationAction
  {
     void navigate(RequestCycle requestCycle);
  }

  /* action to navigate back to this page. */
  private final INavigationAction backToThisPageNavigationAction = new INavigationAction()
  {
     public void navigate(RequestCycle requestCycle)
     {
        requestCycle.setResponsePage(VenueListPage.this);
     }
  }
Code Block
Panel
Wiki Markup
Panel
Wiki Markup

and then have something like:

unmigrated-wiki-markup
Panel
Code Block

   public VenueDetailsPage(Long venueId, INavigationAction backNavigationAction)
   {
      ...
      add(new Link("cancelButton")
      {
         public void onClick()
         {
            backNavigationAction.navigate(getRequestCycle());
         }
      });
      ...

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.

...

First, why this way of implementing wizard is better than page-oriented style. When you post to an adress1address1, 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.

...

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 small wizard engine, based on principle of Finite State Machine (FSM). It is different from similar flow engines in that states and transitions are themselves objects and can have references to domain model objects. Another key difference is that Easy Wizard does not have its own state besides active/inactive, and refers to domain model when state change should be made. This makes it applicable for a web application, where a user can navigate to a web resource directly and can use Back and Forward browser buttonsdead 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

...

WizardPage class is a main page of this sample. It creates wizard controller and steps/panels.

Code Block
{panel}
   public class WizardPage extends WicketExamplePage {
{panel}

{panel}
     protected static Log log = LogFactory.getLog(WicketExamplePage.class);
{panel}

{panel}
     LoginWizard wizard;
{panel}

{panel}
     // Array of wizard panels
     WizardPanel[] wizardPanels = new WizardPanel[2];
{panel}

{panel}
    /**
     * Constructor
     */
     public WizardPage()
     {
       setVersioned(false);
       WizardFormInputModelSignup rawModel = new WizardFormInputModelSignup();
       IModel wizardModel = new CompoundPropertyModel(rawModel);
{panel}

{panel}
       // Each panel is a wizard step. Initialization in the loop cannot
       // be used, because each step defines different model-related methods,
       // thus all steps have different types.
       wizardPanels[LoginWizard.STEP_SIGNUP] =
         new WizardPanelSignup("wp"+LoginWizard.STEP_SIGNUP, wizardModel, this);
       wizardPanels[LoginWizard.STEP_CONFIRM] =
         new WizardPanelConfirm("wp"+LoginWizard.STEP_CONFIRM, wizardModel, this);
{panel}

{panel}
       wizard = new LoginWizard(rawModel, wizardPanels);
{panel}

{panel}
       // Add all panels to wizard page
       for (int i = 0; i < wizardPanels.length; i++) {
         add(wizardPanels[i]);
       }
       updatePanels();
     }
{panel}

{panel}
     public void onCancel() {
       wizard = null;
       updatePanels();
     }
{panel}

{panel}
     public boolean onBack() {
       boolean movedBack = false;
       if (wizard != null) {
         movedBack = wizard.back();
       }
       updatePanels();
       return movedBack;
     }
{panel}

{panel}
     public boolean onNext() {
       boolean movedNext = false;
       if (wizard != null) {
         movedNext = wizard.forward();
       }
       updatePanels();
       return movedNext;
     }
{panel}

{panel}
     /**
      * Hide all panels except one that corresponds to current wizard step.
      * If wizard is not active or is disposed, then all panels are hidden.
      */
     public void updatePanels() {
       for (int i = 0; i < wizardPanels.length; i++) {
         wizardPanels[i].setVisible(
           wizard != null &&
           ("wp"+i).equals(wizard.getCurrentStepName())
         );
       }
     }
   }
{panel}

The wizard controller is defined in LoginWizard class. It defines the transition from Signup step to Confirm step:

Code Block
{panel}
   wizardSteps[STEP_SIGNUP].addOutgoingTransition(
     new WizardTransition(this, "Login To Confirm", wizardSteps[STEP_CONFIRM]) {
       public boolean validate() {
         LoginWizard wizard = (LoginWizard)this.getWizard();
         WizardFormInputModelSignup model = wizard.getModel();
         return model.isValidNameAndPassword();
       }
     }
   );
{panel}

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.

...