M41k Dev3lops M41k Dev3lops - 23 days ago 10
Python Question

Override Jinja block in included template from extending template

I have a Flask project with the Materialize CSS framework. I would like to add

class="active"
to
li
element in navigation menu based on the current page the user is viewing. My main template includes a template with the menu, the menu defines a block for each item's class. The rendered template extends main and overrides one of the blocks, but that doesn't work. How can I override a block defined in an include?

main.html


<div class="menu_container">
{% include "menu_items.html"%}
{% block body %}{% endblock %}
</div>


menu_items.html


<li class="{% block home_active %}{% endblock %}">Homepage</li>
<li class="{% block other_page_active %}{% endblock %}">Other Page</li>


homepage.html


{% extends main.html %}
{% block home_active %}active{% endblock %} #Trying to add class active, doesn't work.
{% block body %}
# Homepage content goes here
{% endblock %}

Answer

This behavior seems logical, but currently you cannot override an included block from a child template. This feature has been implemented once, but got reverted because it had some backward-incompatible side effects.

But there's a workaround of course. The simplest solution is to put every block definition in the main.html template, then extending it in homepage.html will work.

The second solution is to use a global variable, since assignments in child templates are global and executed before the template is evaluated. Here is an example:

main.html

Here we define a variable active_item, which can be override from a child template. We set a default value for it as well.

{% set active_item = active_item|default('home') %}
<div class="menu_container">
    {% include "menu_items.html"%}
    {% block body %}{% endblock %}
</div>

menu_items.html

We add the active class to an item depending of active_item variable.

<li class="{% if active_item == 'home' %}active{% endif %}">Homepage</li>
<li class="{% if active_item == 'other' %}active{% endif %}">Other Page</li>

homepage.html

In this template we set a value to the active_item variable.

{% extends 'main.html' %}    
{% set active_item = 'home' %}

{% block body %}
    # Homepage content goes here
{% endblock %}
Comments