Dynamic Web Development with Seaside

13.1Sequencing Components

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 go method:

WATask subclass: #GuessingGameTask
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'SeasideBook'
GuessingGameTask>>go
| 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!'

The method go randomly draws a number. Then, it asks the user to guess a number and gives feedback depending on the input number. The methods request: and inform: create components (WAInputDialog and 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.

Guessing Game interaction
Why not try modifying the game to count the number of guesses that were needed?

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 call: and 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.

Copyright © 19 March 2024 Stéphane Ducasse, Lukas Renggli, C. David Shaffer, Rick Zaccone
This book is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 license.

This book is published using Seaside, Magritte and the Pier book publishing engine.