[Seaside] Anchor Actions in Rendered Components
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
> html divNamed: 'counter' with: waCounterInstance
> no more changes happen to the display (except if I use the same
> 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
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
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.
More information about the Seaside