Sub-Rendering¶
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 tdi.tools import javascript
template = html.from_string("""
<html>
<body>
<tdi tdi="-script">
<div tdi="*html"><h1 tdi="h1">dynamic js-only-content</h1></div>
<script tdi="*script">
document.write('__html__')
</script>
</tdi>
</body>
</html>
""".lstrip())
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))
template.render(Model())
The example produces the following output:
<html>
<body>
<script>
document.write('<div><h1>My Heading<\/h1><\/div>')
</script>
</body>
</html>
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.