// you’re reading...

Development

Ajax Wizards in Wicket

Lately I’ve found that Wicket + Ajax == Very nice. More then nice its turns out its just a lot easier to build sites using Ajax and Wicket then it is to do it otherwise. Last night I found myself wanting to place a wizard into an entirely Ajax driven site. Luckily Google pointed me to the answer in this thread: Ajax Wizard Button in Modal Window.

In the spirit of duplicating information all over the internet I’ll paste my copy/paste implementation of the presented solution. It works well!

Step 1: Create the AjaxWizardButton class

  1. import org.apache.wicket.ajax.AjaxRequestTarget;
  2. import org.apache.wicket.ajax.markup.html.form.AjaxButton;
  3. import org.apache.wicket.extensions.wizard.IWizard;
  4. import org.apache.wicket.extensions.wizard.IWizardModel;
  5. import org.apache.wicket.markup.html.form.Form;
  6. import org.apache.wicket.model.ResourceModel;
  7.  
  8. public abstract class AjaxWizardButton extends AjaxButton {
  9.  
  10.         private static final long serialVersionUID = 1L;
  11.         private final IWizard wizard;
  12.  
  13.         public AjaxWizardButton(String id, IWizard wizard, final Form form,
  14.                         String labelResourceKey) {
  15.                 super(id, form);
  16.                 this.setLabel(new ResourceModel(labelResourceKey));
  17.                 this.wizard = wizard;
  18.         }
  19.  
  20.         public AjaxWizardButton(String id, IWizard wizard, String labelResourceKey) {
  21.                 this(id, wizard, null, labelResourceKey);
  22.         }
  23.  
  24.         protected final IWizard getWizard() {
  25.                 return wizard;
  26.         }
  27.  
  28.         protected final IWizardModel getWizardModel() {
  29.                 return getWizard().getWizardModel();
  30.         }
  31.  
  32.         protected final void onSubmit(AjaxRequestTarget target, Form form) {
  33.                 onClick(target, form);
  34.         }
  35.  
  36.         protected abstract void onClick(AjaxRequestTarget target, Form form);
  37. }

Step 2: Create the buttonbar that will wrap these buttons and override the native buttonbar built into the Wizard.

  1.  
  2.  
  3. import org.apache.wicket.ajax.AjaxRequestTarget;
  4. import org.apache.wicket.extensions.wizard.IWizardModel;
  5. import org.apache.wicket.extensions.wizard.IWizardStep;
  6. import org.apache.wicket.extensions.wizard.Wizard;
  7. import org.apache.wicket.extensions.wizard.WizardButtonBar;
  8. import org.apache.wicket.markup.html.form.Form;
  9.  
  10. public class AjaxWizardButtonBar extends WizardButtonBar {
  11.  
  12.         private static final long serialVersionUID = 1L;
  13.  
  14.         public AjaxWizardButtonBar(String id, final Wizard wizard) {
  15.                 super(id, wizard);
  16.  
  17.                 addOrReplace(new AjaxWizardButton("next", wizard, "next") {
  18.                         @Override
  19.                         protected void onClick(AjaxRequestTarget target, Form form) {
  20.                                 IWizardModel wizardModel = getWizardModel();
  21.                                 IWizardStep step = wizardModel.getActiveStep();
  22.  
  23.                                 // let the step apply any state
  24.                                 step.applyState();
  25.  
  26.                                 // if the step completed after applying the state, move the
  27.                                 // model onward
  28.                                 if (step.isComplete()) {
  29.                                         wizardModel.next();
  30.                                 } else {
  31.                                         error(getLocalizer()
  32.                                                         .getString(
  33.                                                                         "org.apache.wicket.extensions.wizard.NextButton.step.did.not.complete",
  34.                                                                         this));
  35.                                 }
  36.  
  37.                                 target.addComponent(wizard);
  38.                         }
  39.  
  40.                         public final boolean isEnabled() {
  41.                                 return getWizardModel().isNextAvailable();
  42.                         }
  43.                 });
  44.  
  45.                 addOrReplace(new AjaxWizardButton("previous", wizard, "prev") {
  46.                        
  47.                         protected void onClick(AjaxRequestTarget target, Form form) {
  48.                                 getWizardModel().previous();
  49.                                 target.addComponent(wizard);
  50.                         }
  51.  
  52.                         public final boolean isEnabled() {
  53.                                 return getWizardModel().isPreviousAvailable();
  54.                         }
  55.                 });
  56.         }
  57.  
  58. }
  59.  

Step 3: Alter your wizard html markup so you can override the native buttonbar

  1.  
  2. <html xmlns:wicket>
  3. <wicket:panel>
  4. <div>
  5. <form wicket:id="form" class="wicketExtensionsWizardForm">
  6.  
  7. <span wicket:id="overview"></span>
  8. <span wicket:id="header"></span>
  9.  
  10. <div wicket:id="view"></div>
  11.  
  12. <span wicket:id="feedback"></span>
  13. <div class="buttons">
  14. <span wicket:id="buttons"></span>
  15. </div>
  16. </form>
  17. </div>
  18. </wicket:panel>
  19. </html>
  20.  

Step 4: Set your wizard markup output ID so that you can target it with Ajax calls

  1.  
  2. theWizard.setOutputMarkupId(true);
  3.  

Step 5: Override the buttonbar call in your wizard class

  1.  
  2.         protected Component newButtonBar(java.lang.String id) {
  3.                 return new AjaxWizardButtonBar(id, this);
  4.         }
  5.  

Step 6: Bask in the glow of warm Ajax.

Pretty simple but the impact is fantastic. Using this code I was able to Ajaxify my wizard in well under 10 minutes.

Thanks Wicket!

Discussion

3 comments for “Ajax Wizards in Wicket”

  1. I want to quote your post in my blog. It can?
    And you et an account on Twitter?

    Posted by talaman4eg | December 25, 2009, 1:38 am
  2. Hi, I’ve followed the above instructions carefully. The problem I have is when a component in one of my classes that extends WizardStep fails the error is not rendered. I get the message:

    WARN – WebSession – Component-targetted feedback message was left unrendered. This could be because you are missing a FeedbackPanel on the page. Message: [FeedbackMessage message = [the error message] level = ERROR]

    My Wizard HTML matches that which is above and contains the feedback.

    Any help would be much appreciated.

    Thanks

    Posted by William Froud | January 21, 2010, 7:04 am
  3. Can you post you code?

    Posted by John | January 22, 2010, 9:34 pm

Post a comment