Control flow
Citry gives you two control-flow tools for templates: conditionals (if / elif / else) and loops (for / empty). Each one comes in two forms that do the same thing:
- A tag form, where the control flow is its own
<c-*>element wrapping the content. - A shorthand attribute form, where you put a
c-*attribute directly on the element you want to show or repeat.
Use the tag form when you want to wrap several elements at once, and the shorthand when you are toggling or repeating a single element.
Conditionals
Tag form
Wrap each branch in its own tag. The first branch whose condition is truthy renders; the rest are skipped. <c-elif> and <c-else> are optional.
<c-if cond="is_visible">
<div class="panel">Content</div>
</c-if>
<c-elif cond="is_admin">
<div class="panel">Admin content</div>
</c-elif>
<c-else>
<c-Login />
</c-else>
The branches must be adjacent siblings. Whitespace between them is fine (it is dropped when the branches are grouped), but any other content between two branches is a parse error.
Conditions use normal Python truthiness, not identity. [0] is truthy because it is a non-empty list; [] is falsy. When a <c-if> is falsy and has no matching <c-else>, it renders nothing.
Shorthand form
Put c-if, c-elif, or c-else on a regular element or component. Each one controls just that single element. c-else takes no value.
<div c-if="is_visible" class="panel">Content</div>
<div c-elif="is_admin" class="panel">Admin content</div>
<c-Login c-else />
When the condition is false, the element renders nothing at all.
Loops
Tag form
<c-for> repeats its body once per item. The each clause names the loop variable and the iterable. An optional <c-empty> sibling renders when the iterable produced zero items.
<c-for each="i in items">[{{ i }}]</c-for><c-empty>none</c-empty>
With items=[1] this renders [1]; with items=[] it renders none.
Loop output is escaped like any other expression. If x is <b>, then {{ x }} renders <b>.
Shorthand form
Put c-for on the element you want to repeat, and c-empty on the element to show when there are no items.
<ul>
<li c-for="item in items">{{ item.name }}</li>
<li c-empty>No items found</li>
</ul>
The loop variable is in scope for the rest of that same element too, so you can use it in other attributes on the repeated element (for example a c-bind on the same <li>).
The each clause is a real comprehension
The text inside each is a genuine Python comprehension clause, so anything you can write after for in a comprehension works here.
Unpack multiple targets, including dict items:
<c-for each="k, v in d.items()">{{ k }}:{{ v }} </c-for>
With d={'x': 1, 'y': 2} this renders x:1 y:2.
Filter items with an if:
<c-for each="x in xs if x % 2 == 0">{{ x }}</c-for>
With xs=[1, 2, 3, 4] this renders 24.
Note that a single target over tuples binds the whole tuple. With pairs=[(1, 2), (3, 4)], writing each="p in pairs" and {{ p }} renders (1, 2)(3, 4). Write each="k, v in pairs" to unpack each pair.
The loop variable is only what you name
The only variables bound inside a <c-for> are the targets you write in each. There is no automatic loop object, so there is no loop.index, loop.first, or similar. The loop targets are scoped to the loop body: they do not leak out, and an outer variable of the same name keeps its value after the loop.
To number your items, compute the index in Python with enumerate and pass it in through your template_data. See Expressions for why the template side stays simple: expressions cannot call Python builtins, so work like this belongs in the component.
class Cart(Component):
template = """
<ul>
<li c-for="row in rows">{{ row.i }}: {{ row.name }}</li>
</ul>
"""
def template_data(self, kwargs, slots):
rows = [{"i": i, "name": name} for i, name in enumerate(kwargs["items"])]
return {"rows": rows}
Combining if and for on one element
When you put both c-if and c-for on the same element, the if wraps the for. If the condition is false, the element renders nothing and the loop does not run at all.
Related pages
- Expressions for what you can write inside
cond,each, and{{ }}. - Dynamic attributes for binding attributes such as
c-bindon a looped element.