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.
Brush Message Summary The two following tables show a summary of the most useful textInput
and submitButton
brush methods.