sponsfreixes / jinja2-fragments

Render Jinja2 template block as HTML page fragments on Python web frameworks.
MIT License
232 stars 12 forks source link

Using blocks inside loops? #23

Closed sanzoghenzo closed 9 months ago

sanzoghenzo commented 9 months ago

Hi there, thanks a lot for this great library!

I'm trying to use it with htmx to manage a table, it all works well if I replace the entire table, but if I try to use a block for the single row, then jinja complains about the missing element in the context when rendering the entire page.

{% block projects_table %} <!-- this was used when replacing the entire table -->
<table id="projects_table">
  <thead>...</thead>
  <tbody>
    {% for project in projects %}
      {% block project_row %}  <!-- this i what I'm trying to use now -->
        <tr>
          <td><a href="/projects/{{ project.id }}">{{ project.code }}</a></td>
          <td>{{ project.name }}</td>
          <td>{{ project.created_at }}</td>
        </tr>
      {% endblock %}
    {% endfor %}
  </tbody>
</table>
{% endblock %}

The following is the htmx setup for the new project form;

<form method="post" hx-post="/projects" hx-target="#projects_table" hx-swap="beforeend">

The fastapi endpoints

@router.get("/projects")
async def list_projects(request: Request) -> Response:
    projects = [
        Project(id=i, code=f"Test {i}", name=f"Test Project {i}")
        for i in range(1, 10)
   ]
    return templates.TemplateResponse(
        "list_projects.html.jinja",
        {
            "request": request,
            "projects": projects,
        },
    )

@router.post("/projects")
async def create_project(request: Request) -> Response:
   project = Project(id=10, code="Test10", name="Test Project 10")
    return templates.TemplateResponse(
        "list_projects.html.jinja",
        {"request": request, "project": project},
        block_name="project_row",
    )

I got an error on the get /projects endpoint:

jinja2.exceptions.UndefinedError: 'project' is undefined

Am I using it wrong, or is this a bug?

Obviously, after writing all of this, I realized I can swap the loop and block and pass a single element list, but it feels like a workaround rather than the solution to this problem

sponsfreixes commented 9 months ago

You are using it as I would like it to work. I have to check how Jinja treats variables inside of for loops to figure this one out. Thanks for reporting it!

sponsfreixes commented 9 months ago

Quick update:

I just implemented a test case on a new branch, and it is working as expected.

To be sure, @sanzoghenzo, are you initializing the templates variable with:

from jinja2_fragments.fastapi import Jinja2Blocks
templates = Jinja2Blocks(directory="path/to/templates")

?

sanzoghenzo commented 9 months ago

To be sure, @sanzoghenzo, are you initializing the templates variable with:

from jinja2_fragments.fastapi import Jinja2Blocks
templates = Jinja2Blocks(directory="path/to/templates")

?

Yes, sorry for not mentioning that.

This is embarassing, I should have searched jinja2 documentation first!

I needed to add scoped after the block name to get the correct scoping of the project variable.

Thanks a lot to taking a look at this, and sorry for the wasted time!