Vascula v0.1.5

Loops

#for

for renders its body once for each item of an array.

Template
<ul>{% for tag in product.tags %}<li>{{ tag }}</li>{% endfor %}</ul>
Data
{"data": {"product": {"tags": ["new", "sale"]}}, "allow": ["product"]}
Output
<ul><li>new</li><li>sale</li></ul>

The collection is a single value: a variable path or a range. It cannot take filters; assign a filtered list to a variable first.

Template
{% assign sorted = settings.names | sort %}{% for name in sorted %}{{ name }} {% endfor %}
Data
{"settings": {"names": ["Grace", "Ada"]}}
Output
Ada Grace 

#An empty collection: else

An else inside a loop renders when there is nothing to loop over.

Template
{% for item in settings.items %}{{ item }}{% else %}Your basket is empty.{% endfor %}
Data
{"settings": {"items": []}}
Output
Your basket is empty.

#What can be looped over

ValueIterations
Arrayeach item, in order
Range (a..b)each integer
Map[key, value] pairs, sorted by key; read item[0] and item[1]
nil, missingnone (renders else)
String, number, booleannone (renders else)
Template
{% for pair in settings.sizes %}{{ pair[0] }}={{ pair[1] }} {% endfor %}
Data
{"settings": {"sizes": {"m": 10, "l": 4, "s": 0}}}
Output
l=4 m=10 s=0 

#limit, offset, reversed

Modifiers come after the collection, in any order: offset skips items, limit caps how many remain, and reversed reverses the selection.

Template
{% for n in (1..10) offset: 2 limit: 3 %}{{ n }}{% endfor %} {% for n in (1..10) limit: 3 reversed %}{{ n }}{% endfor %}
Output
345 321

offset is applied first, then limit, then reversed. A negative offset is treated as zero; a negative limit means no limit. Both accept a variable or a filter expression: limit: settings.count | plus: 1.

#Ranges

A range loops over integers. Each end is a number or a variable.

Template
{% for i in (1..settings.stars) %}★{% endfor %}{% for i in (settings.stars..4) %}☆{% endfor %}
Data
{"settings": {"stars": 3}}
Output
★★★☆☆

Ranges are limited in size like any other value; see limits.

#forloop

Inside a loop, forloop describes the current iteration.

PropertyValue
forloop.indexposition, starting at 1
forloop.index0position, starting at 0
forloop.rindexpositions remaining, ending at 1
forloop.rindex0positions remaining, ending at 0
forloop.firsttrue on the first iteration
forloop.lasttrue on the last iteration
forloop.lengthnumber of iterations (after offset, limit)
forloop.parentloopthe enclosing loop's forloop, or nil
Template
{% for t in settings.tags %}{{ t }}{% unless forloop.last %}, {% endunless %}{% endfor %} ({{ settings.tags.size }})
Data
{"settings": {"tags": ["red", "green", "blue"]}}
Output
red, green, blue (3)

In a nested loop, forloop.parentloop reaches the outer loop:

Template
{% for row in (1..2) %}{% for col in (1..3) %}{{ forloop.parentloop.index }}{{ forloop.index }} {% endfor %}{% endfor %}
Output
11 12 13 21 22 23 

#break and continue

break stops the loop; continue skips to the next item. They act on the innermost loop. Using them outside a loop is an error.

Template
{% for n in (1..10) %}{% if n == 3 %}{% continue %}{% endif %}{% if n > 5 %}{% break %}{% endif %}{{ n }}{% endfor %}
Output
1245

#cycle

cycle prints the next of its values each time it runs, starting over after the last. Each cycle tag keeps its own position.

Template
{% for n in (1..5) %}<tr class="{% cycle "odd", "even" %}">{% endfor %}
Output
<tr class="odd"><tr class="even"><tr class="odd"><tr class="even"><tr class="odd">

#Loop variables

The loop variable exists only inside its loop. Variables you assign inside a loop remain after it; see Scope.

Next: Composition.