Sub-rendering means, that you can prematurely render a node during the regular rendering process (i.e. from within a render_name method). This is useful if you want to process the render result before actually emitting it to the output stream. Sub-rendering is implemented by the node’s → render method.

Note that the node is copied, before it’s subrendered. Changes to the node or its subnodes are not visible to the “regular” rendering process.

Placing a HTML Node Into a Javascript Block

That’s a typical use case. Imagine you have a piece of HTML code, that only makes sense if javascript is enabled, or just a fragment that you need later in your script. TDI cannot natively render HTML within a javascript block (because an inline script is just a piece of text from TDI‘s point of view).

The following example shows how to render the HTML in the regular template context and then remove it (using the content picking method with node.replace()) and placing it in the javascript content afterwards. It’s surprisingly simple, given that this explanation takes much more space than the code itself:

from tdi import html
from import javascript

template = html.from_string("""
    <tdi tdi="-script">
    <div tdi="*html"><h1 tdi="h1">dynamic js-only-content</h1></div>
    <script tdi="*script">

class Model(object):
    def render_h1(self, node):
        node.content = u"My Heading"

    def render_script(self, node):
        html = node.html.render()
        javascript.fill(node.replace(None, node.script), dict(html=html))


The example produces the following output:

        document.write('<div><h1>My Heading<\/h1><\/div>')

The code uses the javascript.fill() function, which is part of the javascript tools.

Also note, how the contents of the node is rendered using the current model. The options of the render() method are described in the API documentation.

Using A Different Model

The subrender mechanism uses the current model structure by default. That way, the nodes are properly handled within their scopes. There are, however, use cases, where it’s useful to provide a different model. If you pass your own model, it acts as a “root” model: you might need to rebuild your scope structure.