Number Ranges and their Iteration

The range helper is useful if you need to iterate over numbers in a given range in the template for some purpose.

The easiest way to use it is like this:

{{#range from to}}
{{@value}}
{{/range}}

from is the name of a variable with a number where the lower bound is written, from which we will start our range.

to is the name of a variable with a number, in which the upper bound is written, at which the execution of the of the range block body will end. It is important that this boundary is not included in the range itself.

That is, if we write 1 in the variable from, and 10 in the variable to, we will get numbers from 1 to 9 inclusive.

To use range, it is not necessary to use variables, you can directly specify the number of boundaries:

{{#range 1 10}}
{{@value}}
{{/range}}

For example, such an entry will output numbers from 1 to 9.

Range also allows you to change the step arbitrarily:

{{#range 1 10 step=2}}
{{@value}}
{{/range}}

The step=2 parameter indicates that you need to move through the range in steps of 2. Such an entry will output the numbers 1, 3, 5, 7, 9.

That is, first 1 gets into the helper body, then 2 will be added to it - 1 + 2 = 3, etc. until the helper reaches its upper unattainable boundary.

Two special variables can be used inside the range block: @value, which you could see above, and @index.

@value is the current value of the range.

@index is the sequence number of the current iteration, starting from zero. It is not affected by the step parameter. That is, 0 will be for the first time in @index, 1 will be for the second time, for the third time it will be 2, etc., until the obtaining of numbers in the range ends.

You can clearly see the difference between @index and @value by example:

{{#range 1 10 step=2}}
index: {{@index}} | value: {{@value}}
{{/range}}

The result will be as follows:

index: 0 | value: 1
index: 1 | value: 3
index: 2 | value: 5
index: 3 | value: 7
index: 4 | value: 9

The range can also go in reverse order, for this the lower bound must be greater than the upper one:

{{#range 10 1 step=2}}
{{@value}}
{{/range}}

Result:

10
8
6
4
2

i.e. we can get the numbers in reverse order.

Non-standard list iteration

We can combine the range helper with the get helper, which is used to get values from dictionaries and lists.

Let's say we have the names variable, which stores a list of names of people invited to a party:

{
"names": ["Alex", "Jane", "Mary", "Ann", "Mortimer", "Maxim"]
}

For example, using range and get, we can write such a template to show only even names in the list:

{{#range 1 names.length step=2}}
{{get names @value}}
{{/range}}

Result:

Jane
Ann
Maxim

Let's look at this example in more detail.

We created a block with a range from 1 to the value of the names.length variable. All lists have a nested length variable, which we can access through a dot - it stores the current length of the list.

It turns out that we created a range from 1 to the length of the list. Please note that the list items are numbered not from 1, as we are used to in everyday life, but from 0, as is common in computer programs. Therefore, the number 1 that we get at the first step of our range is the second item in the list, not the first.

Inside the range block we wrote {{get names @value}}.

get is the name of the helper to get items from lists and dictionaries.

names is the name of a variable with a list inside, the first parameter for get.

@value - as we already know - is an internal variable with the current range value at this step.

At each step of the range, we get the index value from @value from names.

Since we have set the range with the parameter step=2, it will increase by 2, i.e. in @value we will get: 1, 3 and 5 - these are just the indexes of even names. Remember that? The order of the elements in the lists starts from 0, i.e. index 1 is the second element, 3 is the fourth, and 5 is the sixth.

Output the list in the reverse order

If you need to output the list in the reverse order, this can also be done via range:

{{#range names.length 0}}
{{get names (subtract @value 1)}}
{{/range}}

In this case, we add another helper subtract that is subtraction.

We create a range in the opposite direction from the length of the list to zero.

Do not forget that the second boundary of the range is not included, and the length of the list is always greater than the index of the last element, because lists are indexed from 0, not from 1.

For this reason, the range is not fully suitable for getting elements, and we need to subtract 1 from the values of the range, for which we use subtract together with get inside the range block.

Output the list

However, if for some reason it is necessary, range can also be used for normal list iteration, although the #each helper is better suited for these purposes:

{{#range 0 names.length}}
{{get names @value}}
{{/range}}

Better with #each:

{{#each names}}
{{this}}
{{/each}}

Creating JSON from a range

Another possibility that ranges provide is the rapid creation of a JSON list with the strinigify helper:

{{stringify (range 1 10 step=2)}}

JSON result:

[1,3,5,7,9]

Such a list can be written to a variable using the Assign a Variable component or Assign Variables with the Object type from JSON.

Limitations

For technical reasons, the range helper is limited to 1000 iterations. This means that you can generate a range from 1 to 1000 inclusive with the step=1 parameter or from 1 to 2000 inclusive with the step=2 parameter. That is, 1000 iterations is a restriction on exactly what you write inside the range block, or a limit on the length of the final list that you will try to get through stringify.

To the beginning ↑