The most important feature of AJAX is the ability to update parts of a page, without having the browser request and parse a whole new page from scratch. This is important since in most web applications only small parts of a page change with each user interaction.
If you look carefully at your todo list page in the browser, you’ll notice that the colour of your todo items doesn’t change when you mark them as completed. It would be nice if we could change the colour of a todo item depending on its state and give the user visual feedback. Let’s make the following change to our code:
self renderHeadingOn: html.
html form: [
id: (listId := html nextId); "<-- ensure you have this"
with: [ self renderItemsOn: html ].
callback: [ self add ];
text: 'Add' ].
html render: editor
ToDoListView>>renderItem: anItem on: html
class: 'done' if: anItem isDone;
class: 'overdue' if: anItem isOverdue;
onChange: (html scriptaculous updater "<-- added"
triggerForm: (html scriptaculous element up: 'form');
callback: [ :ajaxHtml | self renderItemsOn: ajaxHtml ]);
value: anItem done;
callback: [ :value | anItem done: value ].
html text: anItem title.
callback: [ self edit: anItem ];
callback: [ self remove: anItem ];
with: 'remove' ]
We asked Seaside for a unique ID using
html nextId. We store this ID in an instance-variable and assign it to the unordered list in
renderContentOn: to be able to refer to it in
renderItem:on: as a target of an AJAX update action.
renderItem:on: we replaced the
requestor method with an
updater, which understands many of the same messages as a
requestor, but can also update the page once the form’s callbacks have been processed. Since we still want the server to process the changes to the form, we keep the line that triggers the form. To allow the update to happen, we need to give the updater two new pieces of information.
First, we pass the ID of the DOM element that we want it to update. When the update happens, that whole section of your page will be removed, and replaced by some new content that you must specify.
Second, in order to specify the new content, we create a callback block which will be triggered to render. Notice that we pass a new renderer
ajaxHtml to the callback block; the block uses this renderer to render the list of items. Also notice that the checkbox has two callbacks now: one responsible for the state of the checkbox, the other one responsible to update the HTML.
It is important that you use only the renderer passed as argument to the AJAX callback block. Do not to use the
html canvas of the outer context.
html is invalid at the time the AJAX callback is triggered since it already has been sent out to the web browser when the full page request was processed.
If you play with the application you will see that the state of the checkboxes is submitted now. You can observe that the colors of the individual items change as you click the checkboxes, this is because the updater re-renders the listing with the changed items.