[Seaside] Scriptaculous and multiple updates

Pavel Krivanek squeak3 at continentalbrno.cz
Mon Aug 7 07:52:55 UTC 2006

Hi all,

I was experimenting with multiple updates in Scriptaculous. I tried to
create a page with several components that are observing one model
(person). The goal was to create mechanism that enables to refresh all
this components when one of them changes the model. This is the small
schema of the solution.

Every component has to create own div with unique id. Then you have to
create own canvas that use shared callbacks (in the root component)

	^ self painter root renderer callbacks

The root component has hardly assigned renderer that is firstly set in
the renderContentOn: method. You loose some Seaside features this way
but it's normal for ajax applications. 	You also has to use one form
for whole application (here with id #formId). This form is rendered in
the root component.

Then you create updateScript as the part of the renderContentOn:
method of the root component.

	updateScript := ((SUUpdater on: self renderer)
		triggerForm: #formId;
		evalScripts: true;
		id: updaterId;
		callback: [:h |
			| script |
			script := self session updateScriptFor: self renderer.
			h script: script.]) displayString.

The updaterId is id of a div that is also rendered in the root
component. Update Javascript code is placed here and evaluated.

In the session you have the set of components that have to be updated
during next ajax request. It's named componentsToUpdate. Then the
updateScript generator looks like this:

updateScriptFor: html

	| script |
	script := String streamContents: [:s |
		self componentsToUpdate do: [:component |
			s nextPutAll: (component updateScriptFor: html).
			s nextPutAll: ';' ] ].
	componentsToUpdate := Set new.
	^ script.

The updateScript for one component looks like this:

updateScriptFor: html

	^ ((SUUpdater on: html)
		id: componentId;
		callback: [:h | self renderComponentOn: h ]) displayString.

The method renderComponentOn: renders the component without the
wrapping div with unique id.

Then you create anchors or buttons in the components this way:

	html button
		onClick: (self root updateScript);
		text: 'Submit'.

Components that have to be updated are registered in the session.

registerToUpdate: aComponent
	componentsToUpdate add: aComponent.

Summary: in the standard Scriptaculous applications you create update
script that updates some page element for every anchor or button. In
this solution you always update one element. Server then places in
this element javascript that process update for all elements the
server wants.

One disadvantage of this solution is that Scriptaculous can return
only one element for update within one respnse. So here the client
sends one request for every single component. Some time ago I was
exerimenting with multiple elements update in one ajax response. It's
possible but I had to use more low-level Javascript code for that on
client side not Scriptaculous.

This can also be enhanced with delegation. You have to modify the
updateScript to be able to render component with all its decorations.
In the call: method you simply add delegation and answer decoration to
the component and you register the calling component for update. It is
working but  unfortunately you are not able to create continuations
(the code after call: is executed immediately).

Maybe we should create some Seaside variant that will work only with
ajax requests (except the first one). IMHO currently it is not
possible to create ajax-only applicaton.

I hope that this e-mail will be useful.

-- Pavel

More information about the Seaside mailing list