Passing data to viewlets from the parent template

To insert a rendered viewlet manager into a page, one uses something like "tal:replace="structure provider: ILeftSide". Of course, viewlet managers are providers, they implement the IContentProvider interface and are looked up with this interface in the 'provider' TALES handler. One particular trick that content providers do is that they allow insertion of TAL data from the template, to make it accessible inside the content provider class. A sort of "parameters", as it is detailed in the README.txt file, chapter "Additional data from TAL". Things are a bit more complicated for the viewlet managers, because the viewlet manager object is created with a new type at runtime, a type which inherits only the minimum information from the new viewlet manager interface. The only way to make the created viewlet manager provide a new interface (as required by the TALESProviderExpression to insert data from the context) is to subclass ViewletManagerBase and use this class as the factory class for the viewlet manager. I'm giving a simplified example, mostly inspired by the zope.contentprovider documentation:

The viewlet manager interface,

class ILeftSide(IViewletManager):
    """The left side"""

which is registered with:

<viewletManager name="ILeftSide" provides=".ILeftSide"
class=".MessagePassingViewletManager" permission="zope.View" />

The viewlet manager is implemented with this new class:

class MessagePassingViewletManager(ViewletManagerBase):
implements(IMessage)

The class is, as I have found, a key component, because you need it to declare to implement a new interface, the IMessage:

class IMessage(Interface):
message = TextLine(u'Some message')

And the IMessage interface is declared as having a type, zope.contentprovider.interfaces.ITALNamespaceData

<zope:interface interface=".interfaces.IMessage"
type="zope.contentprovider.interfaces.ITALNamespaceData" />

The idea is that all attributes specified in the IMessage interface can then be specified as attributes for the element that renders the viewlet manager in the template:

<div tal:define="message string:Hello World"
            tal:replace="structure provider:ILeftSide" />

Then, in any viewlet subscribed to the ILeftSide manager, you' can have:

<div tal:content="view/manager/message" />

which will render of course the 'Hello world' string. You can actually pass any object this way, there's no constraint imposed by the type defined in the interface schema, as I could tell from my tests.

Comments