render_if
: Conditional Parts in Nevow Templates
This Nevow renderer has saved me a lot of time:
def render_if(self, ctx, data):
r=ctx.tag.allPatterns(str(bool(data)))
return ctx.tag.clear()[r]
Use it like this:
<nevow:invisible nevow:render="if" nevow:data="items">
<ul nevow:pattern="True"
nevow:render="sequence">
<li nevow:pattern="header">The items are a-coming!</li>
<li nevow:pattern="item">(the items will be here)</li>
</ul>
</nevow:invisible>
And now, if the list returned by data_items
is empty, there
will be no <ul>
tag at all in the output.
I just realized non-boolean tests may be wanted -- for example, test
if a string matches a regexp. You could do that by mangling the data
before render_if
, but that's not nice, because then you don't have
access to the original data inside nevow:pattern="True"
. So,
instead let's parametrize the test:
def render_ifparam(self, name):
tester = getattr(self, 'tester_%s' % name, None)
if tester is None:
callable = lambda context, data: context.tag[
"The tester named '%s' was not found in %r." % (name, self)]
return callable
def f(ctx, data):
r=ctx.tag.allPatterns(str(bool(tester(data))))
return ctx.tag.clear()[r]
return f
Note how we still cast the return value of the tester to boolean. You
could avoid that and call the renderer render_switch
. Adding
support for Deferred tests would be quite easy, too. The only ugly
part is I don't know of any way to make the same renderer work nicely
for nevow:render="if"
and nevow:render="ifparam foo"
.
[Updated to add return f
, also renamed second render_if
to
render_ifparam
to clarify things a bit. Thanks k3mper
.]