Introduction
In this tutorial taking an in-depth look at all the options available to us when we loop over arrays.
On our demo Bakery Store site we have cupcake.html
which lists all the cupcakes available:
---
layout: page
title: Muffins
---
<h1>Our cupcakes</h1>
<div class="cupcakes">
{% for cupcake in site.cupcakes %}
<div class="cupcake">
<div class="image">
<img src="{{ cupcake.image_path }}" alt="{{ cupcake.type }}" />
</div>
<h2>{{ cupcake.type }}</h2>
<p>{{ cupcake.description }}</p>
</div>
{% endfor %}
</div>
Cycle
First we’ll add an image filter in CSS to make all the images black and white:
...
<img src="{{ cupcake.image_path }}" alt="{{ cupcake.type }}" style="-webkit-filter: grayscale(100%)" />
...
Let’s change the image filter for each image. We’ll make the first image black and white, the second sepia, the third inverted and then cycle through those options for the rest of the images. To do this we’ll use a cycle
. A cycle
has values it iterates over each time it’s called:
...
<img src="{{ cupcake.image_path }}" alt="{{ cupcake.type }}" style="-webkit-filter: {% cycle "grayscale", "sepia", "invert" %}(100%)" />
...
Index
Next we’ll number the cupcakes. We can access the current iteration of the loop using forloop.index
:
...
<h2>{{ forloop.index }}. {{ cupcake.type }}</h2>
...
We can make the 0 indexed if we use forloop.index0
:
...
<h2>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
...
First and last
Let’s change the first and last cupcakes so the title is white text on a black background. We can check it’s the first or last item in the loop using forloop.first
and forloop.last
:
...
<h2
{% if forloop.first or forloop.last %}
style="background: black; color: white;"
{% endif %}
>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
...
Rindex
If we want to change the highlighting to the last three items instead of the first and the last we could use forloop.rindex
. rindex
gives us how many iterations are left in the loop. So on the first iteration the forloop.rindex
will be six, on the second it would be five and on the last it would be one. We can also use forloop.rindex0
to have a zero indexed number:
...
<h2
{% if forloop.rindex <= 3 %}
style="background: black; color: white;"
{% endif %}
>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
...
Length
When you hover over a heading on the cupcakes page, let’s make it popup with the total number of cupcakes available. I could get the size from the collection using site.cupcakes.size
or we could get it from the forloop using forloop.length
:
...
<h2
{% if forloop.rindex <= 3 %}
style="background: black; color: white;"
{% endif %}
title="{{ forloop.length }} cupcakes"
>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
...
Continue
We can use a continue
to skip straight to the next item in the loop. In this example we’ve skipped over the Lemon cupcake:
...
{% for cupcake in site.cupcakes %}
{% if cupcake.type == "Lemon" %}
{% continue %}
{% endif %}
<div class="cupcake">
<div class="image">
<img src="{{ cupcake.image_path }}" alt="{{ cupcake.type }}"
style="-webkit-filter: {% cycle "grayscale", "sepia", "invert" %}(100%)"
/>
</div>
<h2
{% if forloop.rindex <= 3 %}
style="background: black; color: white;"
{% endif %}
title="{{ forloop.length }} cupcakes"
>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
<p>{{ cupcake.description }}</p>
</div>
{% endfor %}
...
Break
We can use break
to exit the loop. In this example we’re dropping out of the loop when it gets to the Lemon cupcake:
...
{% for cupcake in site.cupcakes %}
{% if cupcake.type == "Lemon" %}
{% break %}
{% endif %}
<div class="cupcake">
<div class="image">
<img src="{{ cupcake.image_path }}" alt="{{ cupcake.type }}"
style="-webkit-filter: {% cycle "grayscale", "sepia", "invert" %}(100%)"
/>
</div>
<h2
{% if forloop.rindex <= 3 %}
style="background: black; color: white;"
{% endif %}
title="{{ forloop.length }} cupcakes"
>{{ forloop.index0 }}. {{ cupcake.type }}</h2>
<p>{{ cupcake.description }}</p>
</div>
{% endfor %}
...
Reversed
Let’s get rid of the break statement and try reversing the order of the loop. We can do this by passing reversed to the for loop:
...
{% for cupcake in site.cupcakes reversed %}
...
Limit and offset
We can add a limit
to a show maximum of three cupcakes and an offset
which skips over the first x number of cupcakes:
...
{% for cupcake in site.cupcakes reversed limit: 3 offset: 3 %}
...
Else
You might need to handle the case where your array is empty. In this example we’ll create an empty flavours array, then we’ll loop over that array and specify an else which is the case where the array is empty:
---
layout: page
title: Muffins
flavours: []
---
...
{% for flavour in page.flavours %}
{{ flavour }}
{% else %}
<h3>There are no flavours</h3>
{% endfor %}
...