Wicket and magical stuff

5 05 2006

So you want Wicket to do more magical stuff for you? Great, because I just added a wizard component to the wicket-extensions.

Wicket wizard

You probably already know, but for the sake of clarity: a wizard component is a dialog component that takes it's users through a number of predefined steps. It has common functionality like a next, previous, finish and cancel button, and it uses a transition rules to let clients navigate through it's steps.

The standard implementation of the wizard component is wicket.extensions.wizard.Wizard, and the interface that abstract what the wizard does/ could do is wicket.extensions.wizard.IWizardModel. This model knows what the current step of the wizard is, and knows what transitions are available – handy for turning buttons on and off – and how these transitions should be made (or how to delegate them). A single step in a wizard is defined in interface wicket.extensions.wizard.IWizardStep and it's default panel based implementation wicket.extensions.wizard.WizardStep. Wizard steps are responsible for managing their state (quite natural, as they are just objects like everything is with Wicket), and deliver the header and main content components (typically panels or fragments).

There is an example in wicket-examples that shows a basic use of the wizard. It shows two not-so-useful static wizards and one form based wizard. If you look at the NewUserWizard example, you can see this in it's constructor:

user = new User();
setModel(new CompoundPropertyModel(this));
WizardModel model = new WizardModel();
model.add(new UserNameStep());
model.add(new UserDetailsStep());
model.add(new UserRolesStep());
model.add(new ConfirmationStep());
init(model);

This is how a wizard and it's model gets configured. A new default wizard model is created, the steps are added in the sequence that they will be executed. An interesting note here – not visible from this code fragment, is that the UserRolesStep is an optional step. The condition is encoded as part of the step itself, but you can also externalize the condition if you prefer that.

Here is what a step looks like (the user name step, of which a screen shot is displayed above).

private final class UserNameStep extends WizardStep {

public UserNameStep() {
    super(new ResourceModel("username.title"), new ResourceModel("username.summary"));
        add(new RequiredTextField("user.userName"));
        add(new RequiredTextField("user.email")
            .add(EmailAddressPatternValidator.getInstance()));
    }
  }
}

The two resource models are for the header component, and will return the localized labels for the title and summary, and the two text fields will work on the parents's CompoundPropertyModel (note that using a required textfield is just short hand for using a text field and setting the required property to true).

The markup of that step looks like this (NewUserWizard$UserNameStep.html):

<wicket:panel>
 <table>
  <tbody>
   <tr>
    <td><wicket:message key="username">Username</wicket:message></td>
    <td><input wicket:id="user.userName" type="text" /></td>
   </tr>
   <tr>
    <td><wicket:message key="email">Email Adress</wicket:message></td>
    <td><input wicket:id="user.email" type="text" /></td>
   </tr>
  </tbody>
 </table>
</wicket:panel>

If your reaction to seeing this is: 'hey, but that's not magical enough for me', do something creative and create a nice useful base step for your case. For example, a panel that analyzes the object (model?) you give it, and based on that creates a dynamic form. Or render an xform definition. The wizard package provide you with a basic working model, and some convenience classes, and the rest is up to you. We wouldn't want to spoil all the programming for you ;).

Check the wizard out in the next release. Hope you'll find it useful.


Actions

Information

One response

1 05 2007
Ralf Eichinger

nice. how to change locale/label for buttons?

Leave a comment