Tasks are used to encapsulate a process or control flow. They do not directly render XHTML, but may do so via the components that they call. Tasks are defined as subclasses of
WATask, which implements the key method
WATask>>go, which is invoked as soon as a task is displayed and can call other components.
Let’s start by building our first example: a number guessing game (which was one of the first Seaside tutorials). In this game, the computer selects a random number between 1 and 100 and then proceeds to repeatedly prompt the user for a guess. The computer reports whether the guess is too high or too low. The game ends when the user guesses the number.
Those of you who remember learning to program in BASIC will recognise this as one of the common exercises to demonstrate simple user interaction. As you will see below, in Seaside it remains a simple exercise, despite the addition of the web layer. This comes as a stark contrast to other web development frameworks, which would require pages of boilerplate code to deliver such straightforward functionality.
We create a subclass of
WATask and implement the
WATask subclass: #GuessingGameTask
| number guess |
number := 100 atRandom.
[ guess := (self request: 'Enter your guess') asNumber.
guess < number
ifTrue: [ self inform: 'Your guess was too low' ].
guess > number
ifTrue: [ self inform: 'Your guess was too high' ].
guess = number ] whileFalse.
self inform: 'You got it!'
go randomly draws a number. Then, it asks the user to guess a number and gives feedback depending on the input number. The methods
inform: create components (
WAFormDialog) on the fly, which are then displayed by the task. Note that unlike the components we’ve developed previously, this class has no
renderContentOn: method, just the method
go. Its purpose is to drive the user through a sequence of steps.
Register the application (as ’guessinggame’) and give it a go. Figure 92 shows a typical execution.
This example demonstrates that with Seaside you can use plain Smalltalk code (conditionals, loops, etc.,) to define the control flow of your application. You do not have to use yet another language or build a scary XML state-machine, as required in other frameworks. In some sense, tasks are simply components that start their life in a callback.
Because tasks are indeed components (
WATask is a subclass of
WAComponent), all of the facilities available to components, such as
answer: messages, are available to tasks as well. This allows you to combine components and tasks, so your
LoginUserComponent can call a
RegisterNewUserTask, and so on.
Tasks do not render themselves. Don’t override
renderContentOn: in your tasks. Their purpose is simply to sequence through other views.
If you are reusing components in a task — that is, you store them in instance variables instead of creating new instances in the
go method — be sure to return these instances in the #children method so that they are backtracked properly and you get the correct control flow.