Loops
A loop repeats a chunk of template for every item in a collection. Use {% for item in items %} in regular paragraphs and {% tr for item in items %} when the loop spans Word table rows.
How to write loops
Plain for loop
{% for product in products %}
{{ product.name }} — {{ product.balance }}
{% endfor %}
Empty-loop else
Renders the {% else %} branch when the collection is empty.
{% for product in products %}
{{ product.name }}
{% else %}
No products to display.
{% endfor %}
Nested loops
{% for category in categories %}
Category: {{ category.name }}
{% for asset in category.assets %}
- {{ asset.name }}: {{ asset.value }}
{% endfor %}
{% endfor %}
Loop variables
Inside a loop you can reference the standard Jinja2 loop object:
loop.index— current iteration, 1-indexed.loop.index0— current iteration, 0-indexed.loop.first—trueon the first iteration.loop.last—trueon the last iteration.loop.length— total number of items.loop.revindex— iterations remaining (1-indexed from the end).
{% for product in products %}
{{ loop.index }}. {{ product.name }}
{% endfor %}
How loops affect field detection
When AdviceDocs parses a loop:
- The collection (
products) is recorded as a parent field withis_array = true. - Child references like
product.nameare recorded under the parent collection (so the editor shows them nested beneathproducts). - The loop variable name (
product) is bound to the collection at extraction time — it doesn’t exist as a standalone field.
Loop variable typo warning
{{ rec_product.name }} in a loop declared as {% for product in products %}), AdviceDocs still records the field but flags it with a warning along the lines of “Did you mean ‘product’ instead of ‘rec_product’?”Configuration after upload
The collection field (e.g. products) appears in the field tree with its is_array flag set. You can give it a description and pick a type for the children, just like any other field. There are no loop-specific settings — the loop is purely a template-time construct.
Common pitfalls
Use {% tr for %} inside Word tables
{% for %} placed in the first cell of a row breaks the table layout because Word XML doesn’t cleanly preserve open-block-then-row-then-close nesting. Use {% tr for item in items %} in the first cell of the looped row and {% endtr %} in the last. See the Tables page for examples.Missing endfor
{% for %} must close with {% endfor %}; every {% tr for %} closes with {% endtr %}. Unbalanced loops raise a Jinja2 syntax error at upload time and the field list won’t generate.Loops can sit inside if blocks
{% if has_products %}{% for p in products %}...{% endfor %}{% endif %}. Each child field inside picks up has_products as a condition dependency.Syntax to copy
{% for product in products %}
{{ product.name }}: {{ product.balance }}
{% endfor %}
{% for product in products %}
{% if loop.first %}Recommended portfolio:
{% endif %}
{{ loop.index }}. {{ product.name }}{% if not loop.last %},{% endif %}
{% endfor %}
{% for product in products %}
{{ product.name }}
{% else %}
No products recommended.
{% endfor %}
Name | Balance |
|---|---|
{% tr for product in products %} | |
{{ product.name }} | {{ product.balance }} |
{% endtr %} | |