DynamicBlock Redux

When I first started working with Tapestry I had just completed a CMS style application with WebObjects. The whole application consisted of a single page component with parts of the page marked as 'dynamic' with logic applied to swap out the contents of these dynamic areas according to some logic based on user navigation and some content scheduling. I wanted the same type of feature in Tapestry without having to pre-declare Blocks containing the components so I could just add components for different content types to a project and get them to just 'show' up on existing pages.

I coded a DynamicBlock component (RenderBlock without the Block) over a year ago for Tapestry 3. My original posts:

DYNAMICBLOCK - CHOOSING TAPESTRY COMPONENTS AT RUNTIME

DYNAMICBLOCK PART II - DYNAMICBLOCK NOW ALLOWS A BODY

I have a new implementation for Tapestry 4 which I believe is cluster-safe since it does not involve modifying the page component structure at run-time. To see the Tapestry 4 version in action click here.

DynamicBlock behaves much like RenderBlock, instead of a block parameter, DynamicBlock accepts a componentName parameter:

<span jwcid="switchBlock@mjh:DynamicBlock" componentName="ognl:selectedComponentName" />


The value passed to the componentName parameter can be computed via your own method, it's up to you how to determine which component should be used.

In addition, DynamicBlock now passes it's informal parameters as parameters of the component which replaces it in the rendered page. So, for example:

<span jwcid="switchBlock@mjh:DynamicBlock" componentName="ognl:selectedComponentName" string="A string value" />


Passes the informal parameter named string as a parameter of the component rendered. The online example and the source code for the example show this feature in action.


DynamicBlock works by pulling a block from a page which wraps the required component. The page name is generated using the componentName value and a custom ISpecificationResolverDelegate supplies the page implementation. The delegate is automatically installed using Hivemind but it honors the org.apache.tapestry.specification-resolver-delegate application extension point as described in the Tapestry 4 Users Guide. The example application includes an implementation of the ISpecificationResolverDelegate which is installed using the application extension mechanism.

Since the components are, in fact, declared in pages (even though the pages are created on-demand) other than the page they are rendered in, these components, or any that they themselves contain must not depend on methods in the PageRenderListener interface for initialization. Since the page which contains them is never rendered, these methods will not be called.

The component is available as a packaged Tapestry library here , and the source code for the example application can be downloaded here.

Declare the library in your .application file:

<library id="mjh" specification-path="/com/mjh/components/mjh-components.library" />

DISCLAIMER: This is fresh code, it seems to work in the testing I have done but there may be issues, feedback is welcome.