Dynamic Web Development with Seaside

10.1Text Input Fields and Buttons

Let’s continue with the same Contact domain model class that we used in Chapter 9. We wish to create a form that allows the user to update the name and email address for a Contact. Smalltalkers are generally very careful to separate presentation from the core of the data model, so we will create a component that will hold the user interface code to allow the user to edit the underlying Contact instance:

WAComponent subclass: #ContactView
instanceVariableNames: 'contact'
classVariableNames: ''
poolDictionaries: ''
category: 'iAddress'

Notice that we’ve specified a contact instance variable; this will be used to hold a reference to the instance of the Contact class that we want to edit. Now we create the accessors for the contact instance variable.

Look carefully at the contact method below. Before returning the value of the contact instance variable, it checks that it has been set. If it hasn’t been set, the code in the block is executed which assigns a sensible value to the variable. This lazy initialisation is a common idiom in Smalltalk code. At the moment we want to test this component as a stand alone component, so the accessor method will lazily load one of the contacts for us.

ContactView>>contact
^ contact ifNil: [ contact := Contact contacts first ]
ContactView>>contact: aContact
contact := aContact

Next, we introduce our first new canvas message: the message form. This method returns an instance of WAFormTag. The only message in WAFormTag of interest to us right now is with: which, as we’ve seen before, takes an argument and renders that argument between the open and close XHTML tags (i.e. the <form> and </form> tags in this case). Controls such as input fields, buttons, popups, list boxes, and so on must all be placed inside a form element.

Forgetting to add the form element is a common mistake. Controls such as input fields, buttons, popups, list boxes etc., must all be placed inside a form tag. If not, they may not be rendered, or they may be rendered but then ignored by the browser.

Our form will have three elements: two text boxes, one each for the name and the email address; and a button for the user to submit their changes.

Let’s look first at the text fields for the name and e-mail address inputs. These fields are created by the canvas’ textInput message which returns a WATextInputTag. For each brush we use two methods value: and callback: . The value: method determines what should be put into this field when it is displayed to the user; here we use the accessor methods on the Contact instance to give these values. The callback: method takes a block that has a single argument. When the user submits the form, the block will have the new contents of the field passed to it using this argument; here we use this to update the Contact instance (via its accessor methods).

Finally we would like our component to have a Save button. We create a button with the canvas submitButton method, which answers a WASubmitButtonTag. We assign a callback so that when the user presses this button the message save is sent.

Here’s the rendering method which creates two text inputs and a submit button:

ContactView>>renderContentOn: html
html form: [
html text: 'Name: '.
html textInput
callback: [ :value | self contact name: value ];
value: self contact name.
html break.
html text: 'Email address: '.
html textInput
callback: [ :value | self contact emailAddress: value ];
value: self contact emailAddress.
html break.
html submitButton
callback: [ self save ];
value: 'Save']
ContactView>>save
"For now let's just display the contact information"
self inform: self contact name , '--' , self contact emailAddress

In Seaside 3.0, the brushes submitButton and textInput you can also use the message value: and with: interchangeably. They both define the contents of the button of text input field.

When the user’s browser submits this form, first all the input callbacks are processed, then the (single) submit button callback will be processed. The order is important because the input callbacks set the corresponding field in the Contact instance. The save method expects those fields to be set before it is invoked.

You should remember that Seaside processes all input field callbacks before the submit button callback.

Register this component as a new application called “contact”, see Section 2.4.5 for details. Point your web browser to http://localhost:8080/contact and you should see the form as shown in Figure 75. Try entering values and submitting the form.

Filling up our contact view

Brush Message Summary The two following tables show a summary of the most useful textInput and submitButton brush methods.

Methods on WATextInputTag Description
callback: aBlockSpecify a single argument callback block which is passed the string value entered by the user.
value: aStringSpecify an initial value for the text input.
on: aSymbol of: anObjectThis is a convenience method explained in the next section.

Methods on WASubmitButton Description
callback: aBlock Specify a zero-argument callback block which is invoked when the user clicks this button.
value: aString Specify a label for this submit button.
on: aSymbol of: anObjectThis is a convenience method explained in the next section.

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.