Nunjucks advanced loops

ยท

5 min read

Nunjucks is a powerful template engine that allows to loop through arrays and also objects ๐Ÿ˜

Loop though an array

{% set animals = ['๐Ÿฑ', '๐Ÿถ', '๐Ÿบ'] %}

{% for item in animals %}
    Value: {{ item }}
{% endfor %}
Value: ๐Ÿฑ
Value: ๐Ÿถ
Value: ๐Ÿบ

Loop though an object

{% set animal = {
    name: 'cat',
    emoji: '๐Ÿฑ'
} %}

{% for key, value in animal %}
    {{ key }}: {{ value }}
{% endfor %}

Note that we have to declare the two parameters of the loop key, value.

name: cat
emoji: ๐Ÿฑ

The iterable property

In Twig exists an intresting property, iterable that checks if a variable can be iterable in a for loop:

Loop through an array:

{% set animals = ['๐Ÿฑ', '๐Ÿถ', '๐Ÿบ'] %}

{% if animals is iterable %}
  {% for item in animals %}
    Value: {{ item }}
  {% endfor %}
{% else %}
  Not iterable: {{ animal }}
{% endif %}
Value: ๐Ÿฑ
Value: ๐Ÿถ
Value: ๐Ÿบ

Loop through an object:

{% set animals = {
  name: 'cat',
  emoji: '๐Ÿฑ'
} %}

{% if animals is iterable %}
  {% for item in animals %}
    Value: {{ item }}
  {% endfor %}
{% else %}
  Not iterable: {{ animal }}
{% endif %}
Value: cat
Value: ๐Ÿฑ

๐Ÿงจ !important

Please note that iterable is a Twig property and can have unexpected results in Nunjucks template engine.

In Twig a string is not iterable:

{% set animal = 'cat' %}

{% if animal is iterable %}
  Iterable!
  {% for item in animal %}
    Value: {{ item }}
  {% endfor %}
{% else %}
  Not iterable!
  {{ animal }}
{% endif %}

Twig output

Not iterable!
cat

but if we run the same code in Nunjucks, we discover that a string is iterable ๐Ÿคฏ

Nunjucks output

Iterable!
Value: c
Value: a
Value: t

Accessing the parent loop

Nunjucks provides in its loops the loop property.

From the docs the loop.index is

the current iteration of the loop (1 indexed)

But what if we have two nested loops and we want to access to the parent loop?

Workaround: save the loop index as row number! ๐Ÿ˜

In this example we have a matrix content: two rows and each row has one ore more cells. If we want to print all cells content and position, we have to:

  • loop (parent loop) through the rows
  • loop (child loop) through the columns
  • get the content inside each cell
{% set animals = [
    ['๐Ÿฑ', '๐Ÿถ', '๐Ÿบ'],
    ['๐Ÿ']
] %}

<table>
  {% for row in animals %}
    {# new row #}
    <tr>
    {% set rowloop = loop %}
    {% for cell in row %}
      <td>
          row (rowloop.index):{{ rowloop.index }}
          column (loop.index): {{ loop.index }}
          cell: {{ cell }}
      </td>
    {% endfor %}
    </tr>
  {% endfor %}
</table>

HTML output

<table>
  {# new row #}
  <tr>
    <td>
        row (rowloop.index):1
        column (loop.index): 1
        cell: ๐Ÿฑ
    </td>
    <td>
        row (rowloop.index):1
        column (loop.index): 2
        cell: ๐Ÿถ
    </td>
    <td>
        row (rowloop.index):1
        column (loop.index): 3
        cell: ๐Ÿบ
    </td>
  </tr>
  {# new row #}
  <tr>
    <td>
        row (rowloop.index):2
        column (loop.index): 1
        cell: ๐Ÿ
    </td>
  </tr>
</table>

๐Ÿ“š More info