[Seaside] Anchor Actions in Rendered Components

Avi Bryant avi at beta4.com
Fri May 7 22:21:52 CEST 2004


On May 7, 2004, at 1:04 PM, Giger, Bengt wrote:

> I just jumped into Seaside and am still collecting basic knowledge.
>
> But I have played around a little with WACounter. If I subclass
> WAComponent as MyClass and render it like this
>
> MyClass>>renderContentOn: html
>   waCounterInstance renderContentOn: html
>
> the counter perfectly works. But if I do
>
>   html render: waCounterInstance
>
> or
>
>   html divNamed: 'counter' with: waCounterInstance
>
> no more changes happen to the display (except if I use the same 
> instance
> for all rendering: clicking on one of the first links changes all three
> counter displays, as expected).
>
> As with Bills example, there is no need or no data to return. Perhaps
> I am missed something (I *certainly* did...) but I wonder why the
> Transcript should print a line of text if I implement the children
> method?

If I understand your question correctly, it's this: why do links work 
if you use "subcomponent renderContentOn: html", or if you use "html 
render: subcomponent" *and* implement #children, but not if you use 
#render: without implementing #children?

The answer is this: Seaside has to make several passes through the 
component tree.  One pass is the render pass, where it generates HTML 
and collects callbacks.  When the request comes back, it performs a 
callback pass (actually two of them), where it matches up items in the 
request with the callbacks that were created while rendering.  This is 
where actions (like printing to the transcript) get triggered.
Now, for each subcomponent that gets passed to #render:, a new set of 
callbacks is created.  For Seaside to find these callbacks when doing 
the request processing passes, it has to know about those 
subcomponents.  So #children is a way of telling the framework "hey, 
here are some subcomponents that might have registered some callbacks 
you'd be interested in".  If you don't implement #children, it will 
never find the callbacks, and so the actions will never happen.
Using #renderContentOn: directly is a sneaky way to get around this; 
what happens is the subcomponent gets rendered using its parent's 
renderer, so any callbacks that are registered get registered as if 
they belonged to the parent.  So even without implementing #children, 
they can get found.  However, you're breaking the framework by doing 
this.  For example, try adding a message decoration to the 
subcomponent:

initialize
    waCounterInstance := WACounter new addMessage: 'foo'.

Now compare using #render: with #renderContentOn:.  You'll see that the 
'foo' heading only shows up in the former case.  You'd run into similar 
problems with #call:, #isolate:, #onAnswer:, and many other features.

If you don't need any of those features in a particular case, there's 
no reason to subclass WAComponent.  Just write a view object that 
subclasses Object, and have it implement #renderOn:.  You should then 
be able to pass it to #render: without including it in #children and 
it'll work just fine.

HTH,
Avi



More information about the Seaside mailing list