<p>Just to provide a slight improvement to @Matanya's solution: Instead of filtering the array of Neo blocks, you can limit your query to the blocks you actually want. This way, you're not loading blocks you don't actually need. For example, to only get level one blocks:</p>
<pre class="lang-twig prettyprint-override"><code>{% for module in entry.pageBuilder.level(1).all() %}
</code></pre>
<p>See the <a href="https://github.com/spicywebau/craft-neo/blob/master/docs/templating.md" rel="nofollow noreferrer">Templating docs for Neo</a> for details.</p>

CC BY-SA 4.0
2021-11-30T09:20:31.017Z
Thanks @MoritzLost. This is definitely better
Matanya
CC BY-SA 4.0
2021-12-01T01:10:21.733Z
I was looking in completely the wrong spot for the conditional that was causing the problem. I was looking at the inner conditional and had code blindness for the one on the `for` loop itself. :/ Thanks both for pointing me in the right direction! 
Tyssen
CC BY-SA 4.0
2021-11-30T09:19:09.387Z
2021-11-30T09:19:09.387Z
MoritzLost
<p>This is a Twig exception. When you are using an <code>if</code> condition on the <code>for</code> loop itself Twig has no way of knowing how many elements will be iterated over, or whether it is the first or last element.</p>
<p>See: <a href="https://github.com/twigphp/Twig/issues/687" rel="nofollow noreferrer">https://github.com/twigphp/Twig/issues/687</a></p>
<p>I see that support for using <code>if</code> on <code>for</code> loops was removed altogether on v3:
<a href="https://github.com/twigphp/Twig/commit/dca3f74e49d8a2a3ffebeba826daeb8de014d286#diff-ecec88c33adb7591ee6aa88e29b62ad52ef443611cba5e0f0ecac9b5725afdbaR3" rel="nofollow noreferrer">https://github.com/twigphp/Twig/commit/dca3f74e49d8a2a3ffebeba826daeb8de014d286#diff-ecec88c33adb7591ee6aa88e29b62ad52ef443611cba5e0f0ecac9b5725afdbaR3</a></p>
<p>Craft appears to be using v2, which is why this is still supported.
<a href="https://github.com/craftcms/cms/blob/4330199e5b7001ca85b9d919d81e465dcc275742/composer.json#L52" rel="nofollow noreferrer">https://github.com/craftcms/cms/blob/4330199e5b7001ca85b9d919d81e465dcc275742/composer.json#L52</a></p>
<p>A possible solution would be to use a filter instead, so rather than pruning irrelevant records during iteration, you serve twig the full pre-filtered array in advance.
<a href="https://twig.symfony.com/doc/2.x/filters/filter.html" rel="nofollow noreferrer">https://twig.symfony.com/doc/2.x/filters/filter.html</a></p>
<pre><code>{% for module in entry.pageBuilder.all() | filter(module=&gt;module.level == 1) %}
</code></pre>
<p>Not tested of course</p>

CC BY-SA 4.0
2021-11-30T08:55:24.407Z
2021-11-30T09:01:37.927Z
2021-11-30T09:01:37.927Z
Matanya
<p>I have a Neo field that contains blocks for hero, body, button etc. For every block except hero, I want them to be wrapped in a containing element. So I have this:</p>
<pre><code>{% for module in entry.pageBuilder.all() if module.level == 1 %}
  {% if module.type == 'moduleHero' %}
    {% include '_partials/page-builder/_moduleHero' %}
  {% else %}
    {% if loop.index == 2 %}
      &lt;div class=&quot;container mx-auto&quot;&gt;
        &lt;div class=&quot;px-4 py-12&quot;&gt;
          &lt;div class=&quot;content clearfix&quot;&gt;
      {% endif %}

          {% include '_partials/page-builder/_' ~ module.type %}

      {% if loop.last %}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    {% endif %}
  {% endif %}
{% endfor %}
</code></pre>
<p>I only want the containing element at the beginning and end of the loop.</p>
<p>But with this code I get:</p>
<blockquote>
<p>The &quot;loop.last&quot; variable is not defined when looping with a condition.</p>
</blockquote>
<p>Which I don't understand. Can someone explain why that is?</p>

<loop><plugin-neo>
`loop.last` throws 'variable is not defined when looping with a condition' error
# `loop.last` throws 'variable is not defined when looping with a condition' error

(Asked by: username_0 on 2021-11-30)

I have a Neo field that contains blocks for hero, body, button etc. For every block except hero, I want them to be wrapped in a containing element. So I have this:
{% for module in entry.pageBuilder.all() if module.level == 1 %}
  {% if module.type == 'moduleHero' %}
    {% include '_partials/page-builder/_moduleHero' %}
  {% else %}
    {% if loop.index == 2 %}
      
        
          
      {% endif %}

          {% include '_partials/page-builder/_' ~ module.type %}

      {% if loop.last %}
        
      
    
    {% endif %}
  {% endif %}
{% endfor %}

I only want the containing element at the beginning and end of the loop.
But with this code I get:

The "loop.last" variable is not defined when looping with a condition.

Which I don't understand. Can someone explain why that is?

**Tags:** loop, plugin-neo

---

## 2 answers

### Answer by username_1 on 2021-11-30. Score: 3 | Accepted answer

Just to provide a slight improvement to @Matanya's solution: Instead of filtering the array of Neo blocks, you can limit your query to the blocks you actually want. This way, you're not loading blocks you don't actually need. For example, to only get level one blocks:
{% for module in entry.pageBuilder.level(1).all() %}

See the Templating docs for Neo for details.

> **Comments:**
> **username_2**: Thanks @MoritzLost. This is definitely better  
> **username_0**: I was looking in completely the wrong spot for the conditional that was causing the problem. I was looking at the inner conditional and had code blindness for the one on the `for` loop itself. :/ Thanks both for pointing me in the right direction!   

---

### Answer by username_2 on 2021-11-30. Score: 2

This is a Twig exception. When you are using an if condition on the for loop itself Twig has no way of knowing how many elements will be iterated over, or whether it is the first or last element.
See: https://github.com/twigphp/Twig/issues/687
I see that support for using if on for loops was removed altogether on v3:
https://github.com/twigphp/Twig/commit/dca3f74e49d8a2a3ffebeba826daeb8de014d286#diff-ecec88c33adb7591ee6aa88e29b62ad52ef443611cba5e0f0ecac9b5725afdbaR3
Craft appears to be using v2, which is why this is still supported.
https://github.com/craftcms/cms/blob/4330199e5b7001ca85b9d919d81e465dcc275742/composer.json#L52
A possible solution would be to use a filter instead, so rather than pruning irrelevant records during iteration, you serve twig the full pre-filtered array in advance.
https://twig.symfony.com/doc/2.x/filters/filter.html
{% for module in entry.pageBuilder.all() | filter(module=>module.level == 1) %}

Not tested of course


---

