Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Wizard forms (logical forms that span multiple pages) are often problematic. Given the stateless-ness of the web handling interactions that span multiple pages can be quite tricky. A standard example is the new user registration flow. Because the user is required to part with so much information the entries get split across multiple pages. But the information entry should be validated on each page, retained throughout the flow and submitted in one atomic transaction at the end.

Stripes Wizards

Creating wizard flows in Stripes is actually very simple. At it's simplest it involves writing a single ActionBean to manage the flow between pages and marking it with the @Wizard annotation. Beyond that it's up to you whether you want to use a single event/method to handle navigation, or a method-per-event. Using different events (and therefore methods) per page tend to make it easier to manage the flow. An abbreviated example from Bugzooky looks like this:

Code Block
titleAn example Wizard action bean
 
@Wizard 
@UrlBinding("/bugzooky/Register.action") 
public class RegisterActionBean extends BugzookyActionBean { 
	@ValidateNestedProperties({ 
		@Validate(field="username", required=true, minlength=5, maxlength=20), 
		@Validate(field="password", required=true, minlength=5, maxlength=20), 
		@Validate(field="firstName", required=true, maxlength=50), 
	@Validate(field="lastName", required=true, maxlength=50) 
	}) 
	private Person user; // getter/setters omitted for brevity 

	@Validate(required=true, minlength=5, maxlength=20, expression="this == user.password") 
	private String confirmPassword; // getter/setters omitted for brevity 

	/** 
	 * Validates that the two passwords entered match each other, and that the 
	 * username entered is not already taken in the system. 
	 */ 
	@ValidationMethod 
	public void validate(ValidationErrors errors) { 
		if ( new PersonManager().getPerson(this.user.getUsername()) != null ) { 
			errors.add("user.username", new LocalizableError("usernameTaken")); 
		} 
	} 

	public Resolution gotoStep2() throws Exception { 
		return new ForwardResolution("/bugzooky/Register2.jsp"); 
	} 

	/** 
	 * Registers a new user, logs them in, and redirects them to the bug list page. 
	 */ 
	@DefaultHandler 
	public Resolution registerUser() { 
		new PersonManager().saveOrUpdate(this.user); 
		getContext().setUser(this.user); 
		getContext().getMessages().add( 
		new LocalizableError(getClass().getName() + ".successMessage",
		this.user.getFirstName(), 
		this.user.getUsername())); 

		return new RedirectResolution("/bugzooky/BugList.jsp"); 
	} 
}

When an ActionBean is marked as a wizard Stripes does a few extra things for you:

...

Code Block
titleWizard with a start event
 
@Wizard(startEvents="begin") 
@UrlBinding("/bugzooky/Register.action") 
public class RegisterActionBean extends BugzookyActionBean { 
	.... 
	/** Sends the user to the registration page at the start of the flow */ 
	public Resolution begin() { 
		return new RedirectResolution("/bugzooky/Register.jsp"); 
	} 
	.... 
}

Backward Navigation Issues

...