list, else, items, sep, break, continue - Apache FreeMarker Manual

Unsupported web browser - Use a modern browser to view this website!

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# list, else, items, sep, break, continue

## Synopsis

The simplest form for listing a sequence (or collection) is:

    <#list sequence as item>
        Part repeated for each item
    </#list>

and to list the key-value pairs of a hash (since 2.3.25):

    <#list hash as key, value>
        Part repeated for each key-value pair
    </#list>

But these are just special cases of the generic forms, which are shown below. Note that for simplicity we only show the generic forms for sequence listing; simply replace "`as item`" with "`as key, value`" to get the generic form for hash listing.

Generic form 1:

    <#list sequence as item>
        Part repeated for each item
    <#else>
        Part executed when there are 0 items
    </#list>

Where:

- The `else` part is optional, and is only supported since FreeMarker 2.3.23.
- `sequence`: Expressions evaluates to a sequence or collection of the items we want to iterate through
- `item`: Name of the loop variable (not an expression)
- The various "parts" between the tags can contain arbitrary FTL (including nested `list`-s)

Generic form 2 (since FreeMarker 2.3.23):

    <#list sequence>
        Part executed once if we have more than 0 items
        <#items as item>
            Part repeated for each item
        </#items>
        Part executed once if we have more than 0 items
    <#else>
        Part executed when there are 0 items
    </#list>

Where: see the "Where" section of Form 1 above (and thus the `else` part is optional here too).

## Description

### Simplest form

Assuming `users` contains the `['Joe', 'Kate', 'Fred']` sequence:

Template

    <#list users as user>
      <p>${user}
    </#list>

Output

      <p>Joe
      <p>Kate
      <p>Fred

The `list` directive executes the code between the `list` start-tag and `list` end-tag (the body of `list` from now on) for each value in the sequence (or collection) specified as its first parameter. For each such iteration the loop variable (`user` in this example) will store the value of the current item.

The loop variable (`user`) only exists inside the `list` body. Also, macros/functions called from within the loop won't see it (as if it were a local variable).

Listing hashes is very similar, but you need to provide two variable names after the `as`; one for the hash key, and another for the associated value. Assuming `products` is `{ "apple": 5, "banana": 10, "kiwi": 15 }`:

Template

    <#list products as name, price>
      <p>${name}: ${price}
    </#list>

Output

      <p>apple: 5
      <p>banan: 10
      <p>kiwi: 15

Note that not all hash variables can be listed, because some of them isn't able to enumerate its keys. It's practically safe to assume though that hashes that stand for Java `Map` objects can be listed.

### else directive

Note:

`else` inside `list` is only supported since FreeMarker 2.3.23

The `else` directive is used if when there are 0 items, you have to print something special instead of just printing nothing:

Template

    <#list users as user>
      <p>${user}
    <#else>
      <p>No users
    </#list>

This outputs the same as the earlier example, except when `users` contains 0 items:

Output

      <p>No users

Note that the loop variable (`user`) doesn't exist between the `else` tag and the `list` end-tag, since that part is not part of the loop.

`else` must be literally (means, in the source code) inside the body of the `list` directive. That is, you can't moved it out into a macro or included template.

### items directive

Note:

`items` exists since FreeMarker 2.3.23

The `items` directive is used if you have to print (or do) something before the first list item, and after the last list item, as far as there's at least 1 item. A typical example:

Template

    <#list users>
      <ul>
        <#items as user>
          <li>${user}</li>
        </#items>
      </ul>
    </#list>

Output

      <ul>
          <li>Joe</li>
          <li>Kate</li>
          <li>Fred</li>
      </ul>

If there are 0 items, the above won't print anything, thus you don't end up with an empty `<ul></ul>`.

That is, when the `list` directive has no `as item` parameter, the body of its is executed exactly once if there's at least one item, or not at all otherwise. It's the body of the mandatory nested `items` directive that will be run for each item, and hence it's also the `items` directive that defines the loop variable with `as item`, not `list`.

A `list` directive with `items` also can have an `else` directive:

Template

    <#list users>
      <ul>
        <#items as user>
          <li>${user}</li>
        </#items>
      </ul>
    <#else>
      <p>No users
    </#list>

Some further details:

- The parser will check that a `list` without `as item` parameter always has a nested `items` directive, and that an `items` directive always has an enclosing `list` which has no `as item` parameter. This is checked when the template is parsed, not when the template is executed. Thus, these rules apply on the FTL source code itself, so you can't move `items` out into a macro or included template.

- A `list` can have multiple `items` directives, but only one of them will be allowed to run (as far as you don't leave and re-enter the enclosing `list` directive); and further attempts to call `items` will cause error. So multiple `items` can be utilized on different `if`-`else` branches for example, but not for iterating twice.

- `items` directive can't have its own nested `else` directive, only the enclosing `list` can have

- The loop variable (`user`) only exists inside the body of the `items` directive.

### sep directive

Note:

`sep` exists since FreeMarker 2.3.23

`sep` is used when you have to display something between each item (but not before the first item or after the last item). For example:

Template

    <#list users as user>${user}<#sep>, </#list>

Output

    Joe, Kate, Fred

Above, `<#sep>, </#list>` is a shorthand for `<#sep>, </#sep></#list>`; the `sep` end-tag can be omitted if you would put it where the enclosing directive is closed anyway. In the next example, you couldn't use such abbreviation (HTML tags close nothing, as they are just raw text to output for FreeMarker):

Template

    <#list users as user>
      <div>
        ${user}<#sep>, </#sep>
      </div>
    </#list>

`sep` is just a shorthand for `<#if item?has_next>...</#if>`. Thus, it can be used anywhere where there's a `list` or `items` loop variable available, it can occur for multiple times, and it can have arbitrary nested content.

The parser ensures that `sep` is only used on a place where there's a visible loop variable. This happens earlier than the actual execution of the template. Thus, you can't move `sep` from inside the associated `list` or `items` directive into a macro or included template (the parser can't know where those will be called from).

### break directive

Note:

`break` is deprecated for most use cases, as it doesn't work well with `<#sep>` and `item?has_next`. Instead, use `sequence?take_while(predicate)` to cut the sequence before you list it. See also examples here.

You can exit the iteration at any point with the `break` directive. For example:

Template

    <#list 1..10 as x>
      ${x}
      <#if x == 3>
        <#break>
      </#if>
    </#list>

Output

      1
      2
      3

The `break` directives can be placed anywhere inside `list` as far as it has `as item` parameter, otherwise it can be placed anywhere inside the `items` directive. However, it's strongly recommended to place it either before or after all the other things that you do inside the iteration. Otherwise it's easy to end up with unclosed elements in the output, or otherwise make the template harder to understand. Especially, avoid breaking out from the nested content of custom directives (like `<#list ...>...<@foo>...<#break>...</@foo>...</#list>`), as the author of the directive may not expect that the closing tag (`</@foo>`) is never executed.

If the `break` is inside `items`, it will only exit from `items`, not from `list`. In general, `break` will only exit from the directive whose body is called for each item, and can only be placed inside such directive. So for example can't use `break` inside `list`'s `else` section, unless there's the `list` is nested into another `break`-able directive.

Using `break` together with `sep` or `?has_next` is generally a bad idea, as these can't know if you will skip the rest of items with a `break`. To solve such situations see these examples.

Just like `else` and `items`, `break` must be literally inside body of the directive to break out from, and can't be moved out into a macro or included template.

### continue directive

Note:

`continue` is deprecated for most use cases, as it doesn't work well with `<#sep>`, `item?has_next`, `item?counter`, `item?index`, `item?item_parity`, etc. Instead, use `sequence?filter(predicate)` to remove unwanted elements. See also examples here.

Note:

The `continue` directive exists since FreeMarker 2.3.27.

You can skip the rest of the iteration body (the section until the `</#list>` or `</#items>` tag) with the `continue` directive, then FreeMarker will continue with the next item. For example:

Template

    <#list 1..5 as x>
      <#if x == 3>
        <#continue>
      </#if>
      ${x}
    </#list>

Output

      1
      2
      4
      5

The `continue` directives can be placed anywhere inside `list` as far as it has `as item` parameter, otherwise it can be placed anywhere inside the `items` directive. However, it's strongly recommended to place it before all the other things you do inside the iteration. Otherwise it's easy to end up with unclosed elements in the output, or otherwise make the template harder to understand. Especially, avoid breaking out from the nested content of custom directives (like `<#list ...>...<@foo>...<#continue>...</@foo>...</#list>`), as the author of the directive may not expect that the closing tag (`</@foo>`) is never executed.

When you call `continue`, the `sep` directive will not be executed for that iteration. Using `continue` together with `sep` is generally a bad idea anyway, also `?has_next`, `?counter`, `?index`, `?item_parity`, etc. will not work as you certainly wanted if you completely skip items. To solve such situations see these examples.

Just like `break`, `continue` must be literally inside body of the directive whose iteration need to be "continued", and can't be moved out into a macro or included template.

### Accessing iteration state

Starting from 2.3.23, loop variable built-ins is the preferred way of accessing current state of the iteration. For example, here we use the `counter` and `item_parity` loop variable built-ins (see all of them in the Reference):

Template

    <#list users>
      <table>
        <#items as user>
          <tr class="${user?item_parity}Row">
            <td>${user?counter}
            <td>${user}
        </#items>
      </table>
    </#list>

Output

      <table>
          <tr class="oddRow">
            <td>1
            <td>Joe
          <tr class="evenRow">
            <td>2
            <td>Kate
          <tr class="oddRow">
            <td>3
            <td>Fred
      </table>

In 2.3.22 and earlier, there were two extra loop variables to retrieve the iteration state instead (and they still exist for backward compatibility):

- `item_index` (deprecated by `item?index`): The index (0-based number) of the current item in the loop.

- `item_has_next` (deprecated by `item?has_next`): Boolean value that tells if the current item is the last in the sequence or not.

so in the above example, you could replace `${user?counter}` with `${user_index + 1}`.

### Skipping items conditionally

If you need to skip certain element in a list, it's generally a bad idea to use `if` directive for that, because then `<#sep>`, `item?has_next`, `item?counter`, `item?index`, `item?item_parity`, etc., will not be usable, as FreeMarker doesn't know what items were and will be actually displayed. Instead, you should try to remove the unwanted items from the sequence that you will list, and then list it (since 2.3.29). Here are some typical examples with and without `if`.

#### Filtering

In this example, you want to show the recommended products from `products`. Here's the wrong solution with `if`:

Template

    <#-- WRONG solution! The row parity classes will be possibly messed up: -->
    <#list products as product>
       <#if product.recommended>
         <div class="${product?item_parity}Row">${product.name}</div>
       </#if>
    </#list>

Here's the good solution that uses the `filter` built-in:

Template

    <#-- Good solution: -->
    <#list products?filter(p -> p.recommended) as product>
      <div class="${product?item_parity}Row">${product.name}</div>
    </#list>

#### Stop listing when a certain element is found

Let's say you have a list of lines in `lines`, and you need to stop at the first empty line (if there's any). Furthermore you need to `<br>` between the elements. Here's the wrong solution with `if` and `break`:

Template

    <#-- WRONG solution! <br> might be added after the last printed line: -->
    <#list lines as line>
       <#if line == ''>
         <#break>
       </#if>
       ${line}<#sep><br>
    </#list>

Here's the good solution that uses the `take_while` built-in (note that the condition is inverted compared to the `if`+`break` solution):

Template

    <#-- Good solution: -->
    <#list lines?take_while(line -> line != '') as line>
       ${line}<#sep><br>
    </#list>

### Nesting loops into each other

Naturally, `list` or `items` can contain further `list`-s:

Template

    <#list 1..2 as i>
      <#list 1..3 as j>
        i = ${i}, j = ${j}
      </#list>
    </#list>

Output

        i = 1, j = 1
        i = 1, j = 2
        i = 1, j = 3
        i = 2, j = 1
        i = 2, j = 2
        i = 2, j = 3

It's also allowed to use clashing loop variable names like:

Template

    <#list 1..2 as i>
      Outer: ${i}
      <#list 10..12 as i>
        Inner: ${i}
      </#list>
      Outer again: ${i}
    </#list>

Output

      Outer: 1
        Inner: 10
        Inner: 11
        Inner: 12
      Outer again: 1
      Outer: 2
        Inner: 10
        Inner: 11
        Inner: 12
      Outer again: 2

### Treatment of missing (null) elements

As you know by now, the `list` directive will repeat its nested content for each element of the listed value. However, it's technically possible that you have holes (missing values, Java `null`-s) in the list of elements. The nested content will executed for these "holes" as well, but then the loop variable (the variable whose name you specify after the `as` keyword) will be missing. When FreeMarker finds that there's no variable with the given name in the loop variable scope, it will just fall back to a higher scopes to find it. However, this fallback behavior can be problematic in this case. Consider:

Template

    <#list xs as x>
      ${x!'Missing'}
    </#list>

Here, the intent of the author is to print "Missing" for the missing elements (hopes) of `xs`. But if accidentally there's an `x` variable in a higher scope, like in the data-model, then `x` will evaluate to that in case the currently listed element is missing, and so it won't default to "Missing". To solve that, the programmers should set the `fallback_on_null_loop_variable` configuration setting to `false`. (Unfortunately, the default must be `true` for backward compatibility.) In that case no fallback will occur if a loop variable is missing.

### Notes for Java programmers

If classic compatible mode `list` accepts a scalar too and treats it as a single-element sequence.

If you pass a collection that wraps an `java.util.Iterator` to the `list`, you can iterate over its elements only once, since `Iterator`s are by their nature one-off objects. When you try to list a such collection variable for the second time, an error will abort template processing.

Previous Next