nunjucks: Treating "for" loops as a separate scope does not behave reasonably

This code:

{% set lastDate = '' %}
{% for item in items %}
  {{ renderEvent(event, item, lastDate) }}
  {% set lastDate = item.date %}
{% endfor %}

Does not behave as a programmer accustomed to [fill in pretty much any language here] would expect.

The renderEvent macro receives ‘’ on every iteration, because it sees the lastDate variable declared in the outer scope.

The second set statement creates a separate lastDate variable in an inner scope but it is too late for renderEvent to see it.

If we get rid of the first “set” entirely, the code starts working; renderEvent passes undefined on the first pass, and the value of the second “set” on each pass thereafter.

This works, but it requires us to lean heavily on nunjuck’s tolerance for passing undefined variables, and if we needed to initialize to something other than “nothing” we’d be out of luck.

IMHO a for loop should never create a new variable scope in a language that has no distinction between declaring a variable (“var foo”) and updating it.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 38 (15 by maintainers)

Commits related to this issue

Most upvoted comments

I still don’t think creating new scopes inside “for” loops makes sense in a language without explicit declarations. It’s just not possible to correctly infer what is supposed to happen.

On Tue, Dec 9, 2014 at 3:56 PM, Felipe Nascimento de Moura < notifications@github.com> wrote:

We tried that, we too thought what would be the behaviour, but this did not work, either! When the {% set highlight = image.url %} happens inside the loop, it ignores the “highlight” variable from outside! And it was “killed” in the end of each loop, becoming “” after the endfor statement! The version we are using here is 1.0.4.

— Reply to this email directly or view it on GitHub https://github.com/mozilla/nunjucks/issues/166#issuecomment-66356099.

*THOMAS BOUTELL, *DEV & OPS P’UNK AVENUE | (215) 755-1330 | punkave.com

In the case we are facing here…

{% for image in images %}
    {% if thumbs.selected == image.id %}
        {% set highlight = image.url %}
    {% endif %}
    <img src="image.thumbUrl" />
{% endfor %}
<img src="{{ highlight }}" />

In this case we need to, using the loop, identify the selected thumb to show it afterwards in a bigger size. But it does not work, because the highlight variable is gone! I know that the set token creates the new variable inside the for scope, but how can we get that to work? I see the issue is closed, but couldn’t figure out if this is a bug, or if there is a way to do it, but it is not documented anywhere!

It looks to me like this is an issue with the implementation of set rather than for.