[Seaside] Which class best suits a simple submission form?

Avi Bryant avi at beta4.com
Wed Nov 19 03:20:54 CET 2003


On Nov 18, 2003, at 9:50 AM, Samuel Tesla wrote:

> First off, I love Seaside.  It is very very cool.  But I'm trying to
> follow the examples that are provided to figure out what to do for my
> app, and I can't help but think I'm making it too hard for myself.
>
> What I want to set up is a simple sign up wizard.  Each page would
> verify the data before committing it to the model.  There would be
> buttons like in a normal GUI wizard: next, forward, finish, cancel.  
> The
> buttons would be active/inactive depending on which screen in the 
> wizard
> they were in.

Hi Samuel,

The way I do wizards is this:

- For each step in the wizard, create a Component subclass as well as a 
model class.  The component will, on initialization, create and hang 
onto an instance of this model class.  Sometimes, this will be an 
existing domain object in your system (for example, a step where the 
user enters their address).  Sometimes, it may make more sense to 
create a model object specifically to hold the info needed by this 
step.
- The component should render a form with an input for each attribute 
of the model, as well as a Next submit button.  This button should 
invoke an action method that validates the data.  If the data is 
invalid, you want to inform the user of this somehow.  If it's valid, 
simple #answer: the model object.
- Create a Task subclass to string these steps together.  Say you had 
three steps, collecting name, shipping address, billing address and 
credit card info.  You might have a #go method that looked like this:

MyWizardTask>>go
   |name address billingAddress creditCardInfo|
   name := self call: (GetNameStep new).
   address := self call: (GetAddressStep new message: 'Shipping 
address').
   address useForBilling
      ifTrue: [billingAddress := address]
      ifFalse: [billingAddress := self call: (GetAddressStep new 
message: 'Billing address')].
  creditCardInfo := self call: (GetCCStep new).
  "... now do something with all of this... "

Now, this doesn't provide a "Previous" button, but the browser back 
button works fine.  For Cancel, I would wrap embed this task in another 
component that provided a permanent cancel button:

CancelWrapper>>initialize
    task := MyWizardTask new.

CancelWrapper>>renderContentOn: html
    html render: task.
    html form: [html submitButtonWithAction: [self answer] text: 
'Cancel'].

I'm not sure about Finish, I guess it depends how you want that to work 
(what does it mean to Finish before all the info is entered?).

The great thing to appreciate about this approach is that you can often 
use the same components in various permutations in different #go 
methods to make different wizards (I tried to suggest this somewhat by 
using the same parameterized component for the the two address steps).

I'll try to put a wizard example in the next release.

Cheers,
Avi



More information about the Seaside mailing list