Dynamic Web Development with Seaside

20.4.2Serializing a Form

An annoying behavior of our application is that the user has to click save to submit changes in the todo list. This is not really user-friendly and also dangerous, because it is too easy to forget to hit the save button after toggling the checkboxes. With AJAX we can improve this, and let the browser worry about saving our changes. Let’s use AJAX to automatically submit the form whenever a checkbox is clicked:

ToDoListView>>renderItem: anItem on: html
html listItem
class: 'done' if: anItem isDone;
class: 'overdue' if: anItem isOverdue;
with: [
html checkbox
onChange: (html scriptaculous request "<-- added "
triggerForm: (html scriptaculous element up: 'form'));
value: anItem done;
callback: [ :value | anItem done: value ].
html text: anItem title.
html space.
html anchor
callback: [ self edit: anItem ];
with: 'edit'.
html space.
html anchor
callback: [ self remove: anItem ];
with: 'remove' ]

Once you’ve made this change, load the application in your browser and click on one of the checkboxes. Without pressing save, refresh your browser window, and you should see the new value has ‘stuck’.

Again we are using the request object, but this time instead of a callback we tell it to trigger a form using PTAjax>>triggerForm:. This method expects a DOM ID or DOM node of a form as an argument. We could use the same trick that we used previously and let Seaside generate a unique ID and assign it to the form and to our JavaScript snippet. This technique has the disadvantage that we introduce a new dependency between the method that renders the form and the one that renders the checkbox, which might not be desired.

html scriptaculous element up: 'form'

walks up the DOM tree and returns the first form it encounters. In our case this is the surrounding form of our checkbox. The starting point of this lookup is the current DOM node (our checkbox) since we didn’t specify a different element using PTElement>>id:. If we only used PTElement>>up, we would have got the parent element of the checkbox, which in this example is the div element. There are some other methods defined in PTElement that navigate the DOM tree in other directions: PTElement>>down, PTElement>>next, and PTElement>>previous.

Serializing your data. Once the form element has been found in the DOM, we then want to specify what to do with it:

html request
triggerForm: (html element up: 'form')

Here, the triggerForm: says we want the page to ‘serialize’ the form, that is, to convert the DOM representation of the form (and all its included fields) into a string that can be passed back to the server when required. We pass this serialised version into the request method of the html object, which causes the required JavaScript code to be generated in the page in your browser.

Because all of this happens as an argument to html checkbox onChange:, the script will be generated into the onchange attribute of the checkbox, giving you something like the following:

<input class="checkbox" type="checkbox" name="4" checked="checked" 
    onchange="new Ajax.Request(

So the effect of this code is that when you click on the checkbox, its onchange event gets fired. This creates an Ajax request that is sent back to your server with your serialized form. The Scriptaculous code in Seaside will then process all the callbacks defined in your form, using the data it retrieved from the serialized form.

Obviously the save button is not needed in our example any more and we can remove it, but you could decide to keep the button so that your application would continue to work for people who have JavaScript disabled. Since we still have the button, our application can be used with and without JavaScript support.

Copyright © 22 April 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.