[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