pallets / jinja

A very fast and expressive template engine.
https://jinja.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
10.25k stars 1.6k forks source link

Support HTMX-style functionality #1860

Closed neilmcguigan closed 1 year ago

neilmcguigan commented 1 year ago

HTMX is a JavaScript library to help you avoid writing JavaScript. Makes AJAX requests using HTML attributes, and expects a partial HTML response

Two features of Jinja that would help here:

  1. a return statement

instead of:

{% if "HX-Request" in request.headers %}
  ... partial response
{% else %}
  ... full response
{% endif %}

something like:

{% return "<some-html>" if "HX-Request" in request.headers %}
... full response

return is supported by Mako: https://docs.makotemplates.org/en/latest/syntax.html#exiting-early-from-a-template

  1. Partials/Fragments, like https://github.com/bigskysoftware/chill/tree/master/chill-script

see also https://htmx.org/essays/template-fragments/

These two features would help adopt HTMX usage with Flask, etc, which would increase long-term usage of Flask and Jinja

ThiefMaster commented 1 year ago

That {% return %} statement would not work well with anything but simple strings. If you put html in a quoted string in Jinja, you are almost always doing something wrong.

However, I think it might not be too hard to implement something like this as a custom Jinja extension:

{% return if <some condition> %}

{% endreturn %}

That said, I don't really see the point of it. You can already generate your partial snippets using macros and by creating a template module in your Python code, which allows you to use the template's macros like methods in a Python class. And in the "full" version of your template you'd simply call that macro.

And regarding fragments... macros can almost do the same. I'd say the only real difference is that you usually do not define them at the exact same place where you call them. (Being able to render just a particular {% block %} from a template could be interesting though...)

neilmcguigan commented 1 year ago

by creating a template module in your Python code, which allows you to use the template's macros like methods in a Python class

can you expand on that, or have a link for me? thanks

ThiefMaster commented 1 year ago

Add a util like this (this one is for Flask, didn't bother making one using pure Jinja):

def get_template_module(template_name_or_list, /, **context):
    """Return the python module of a template.

    This allows you to call e.g. macros inside it from Python code."""
    current_app.update_template_context(context)
    tpl = current_app.jinja_env.get_or_select_template(template_name_or_list)
    return tpl.make_module(context)

You call it just like render_template etc. and the returned object is exactly what I mentioned above.

davidism commented 1 year ago

Duplicate of https://github.com/pallets/jinja/issues/1808, my comment there shows how to render blocks or macros individually, or there's https://github.com/sponsfreixes/jinja2-fragments and https://github.com/mikeckennedy/jinja_partials.