tdammers / ginger

A Haskell implementation of the Jinja template language.
MIT License
77 stars 13 forks source link

Passing local variables while including a template? #54

Open saurabhnanda opened 4 years ago

saurabhnanda commented 4 years ago

I'm trying to descend a recursive data-structure and recursively render the same template [1] Forget the recursive part, I'm unable to pass local variables to an included template. I've tried the following, and nothing works:

{% include "includes/toc.html" with tocItems = page.toc %}
{% with tocItems = page.toc %}
  {% include "includes/toc.html" %}
{% endwith %}
{% scope %}
  {% set tocItems = page.toc %}
  {% include "includes/toc.html" %}
{% endscope %}

[1] I'm trying to generate a page's TOC -- which is why the recursion

tdammers commented 4 years ago

Hmm, OK. I think that according to Jinja, this should work, and a quick test using the following pair of templates against the ginger CLI suggests that in fact it does:

(included.html)

Hello, {{ a }}!

(includer.html)

{% for a in [1, 2, 3] %}
{% include "included.html" %}
{% endfor %}

Outputs:

Hello, 1!
Hello, 2!
Hello, 3!

It also works with {% set ... %}.

If you can boil it down to a complete reproduction case (ideally against the ginger CLI program), I can look into it, though it will probably be at least 2 weeks until I get around to it.

with is not currently supported (neither inside {% include %} not as a tag on its own), but would be a great addition, and shouldn't be too difficult to implement.

saurabhnanda commented 4 years ago

Is the only way to pass local variables to a template in this implicit manner? Wouldn't this break down for a recursive template? For example, how would you make something like the following work (it gets stuck in an infinite loop):

template.html

<html>
  <body>
    {% set tocItems = page.toc %}
    {% include 'includes/toc.html' %}
  </body>
</html>

toc.html

<ul>
    {% for tocItem in tocItems %}
      <li>
        <a class="level{{ tocItem.level }}" href="{{ tocItem.link }}">{{ tocItem.text }}</a>
        {% if tocItem.children == [] %}
          <!-- no children -->
        {% else %}
          <!-- with children -->
          {% set tocItems = tocItem.children %}
          {% include 'toc.html' %}
        {% endif %}
      </li>
    {% endfor %}
</ul>
tdammers commented 4 years ago

Frankly, I haven't given this a lot of thought. First place to look would be jinja2; whatever they do, ginger should probably follow.

That said, for a recursive TOC, my go-to approach is to use a macro - these recurse just fine, with proper scope and all.

Something like:

{%- macro toc(tocItems) -%}
<ul>
    {% for tocItem in tocItems %}
      <li>
        <a class="level{{ tocItem.level }}" href="{{ tocItem.link }}">{{ tocItem.text }}</a>
        {% if tocItem.children == [] %}
          <!-- no children -->
        {% else %}
          <!-- with children -->
          {{ toc(tocItem.children) }}
        {% endif %}
      </li>
    {% endfor %}
</ul>
{%- endmacro -%}
srid commented 3 years ago

Wouldn't this break down for a recursive template?

@saurabhnanda Have you found any Haskell HTML template library that supports recursion, while supporting variable binding in proper scope?

It seems to me that only heist supports it. cf. https://github.com/srid/emabook/pull/7 (direct link to simplified recursive template; see line 46)

tdammers commented 3 years ago

Would be interesting what Jinja2 does here. IIRC, it has slightly weird scoping too, though it does includes dynamically (which I didn't, to avoid the possibility of template injection vulnerabilities), so there's going to be some difference anyway.

On Sun, May 16, 2021, 06:38 Sridhar Ratnakumar @.***> wrote:

Wouldn't this break down for a recursive template?

@saurabhnanda https://github.com/saurabhnanda Have you found any Haskell HTML template library that supports recursion, while supporting variable binding in proper scope?

It seems to me that only heist supports it. cf. srid/emabook#7 https://github.com/srid/emabook/pull/7

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/tdammers/ginger/issues/54#issuecomment-841765219, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAK6HR7R7YAV3WJAPFLDRL3TN5D6FANCNFSM4QHBFWWA .