Style Active Navigation Element with a Flask/Jinja2 MACro

Style active navigation element with a Flask/Jinja2 macro

Your code just defines a macro over and over again, it doesn't render anything. Avoid reading request.endpoint and use base templates to do this.

base.html

<ul class="nav nav-pills">
<li class="{% block nav_here %}{% endblock %}">Here</li>
<li class="{% block nav_there %}{% endblock %}">There</li>
<li class="{% block nav_anywhere %}{% endblock %}">Anywhere</li>
</ul>

{% block content %}{% endblock %}

there.html

{% extends "base.html" %}
{% block nav_there %}active{% endblock %}
{% block content %}
<blockquote>No matter where you go, there you are.</blockquote>
{% endblock %}

The base navigation defines empty nav_ blocks in the li class and the sub template sets the relevant one to active. You can extend this as far as you want to have sub-navigation within pages too.

Changing the active class of a link with the twitter bootstrap css in python/flask

Have you looked at this ? https://jinja.palletsprojects.com/en/3.0.x/tricks/#highlighting-active-menu-items

Highlighting Active Menu Items

Often you want to have a navigation bar with an active navigation item. This is really simple to achieve. Because assignments outside of blocks in child templates are global and executed before the layout template is evaluated it’s possible to define the active menu item in the child template:

{% extends "layout.html" %}
{% set active_page = "index" %}

The layout template can then access active_page. Additionally it makes sense to define a default for that variable:

{% set navigation_bar = [
('/', 'index', 'Index'),
('/downloads/', 'downloads', 'Downloads'),
('/about/', 'about', 'About')
] -%}

{% set active_page = active_page|default('index') -%}
...
<ul id="navigation">
{% for href, id, caption in navigation_bar %}
<li{% if id == active_page %} class="active"{% endif
%}><a href="{{ href|e }}">{{ caption|e }}</a>
</li>
{% endfor %}
</ul>

Add a nav bar to all templates

Create a base template with the layout and naviagation that will be common to all pages. Then extend this template to create the actual pages. Add blocks to the base template that can be overriden in the others.

base.html

<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>{% block title %} - My Site {% endblock %}</title>
</head>
<body>
<div>Navbar</div>
{% block content %}{% endblock %}
</body>
</html>

index.html

{% extends 'base.html' %}

{% block content %}
<h3>{% block title %}Home{% endblock %}</h3>
<p>Hello, World!</p>
{% endblock %}

Note that the navbar is just defined in the base template. It does not need a block, and the content from the child templates will be substituded in after it.

You can use a similar technique to control which item is highlighted in a navigation bar.

Style active navigation element with a Flask/Jinja2 macro

Your code just defines a macro over and over again, it doesn't render anything. Avoid reading request.endpoint and use base templates to do this.

base.html

<ul class="nav nav-pills">
<li class="{% block nav_here %}{% endblock %}">Here</li>
<li class="{% block nav_there %}{% endblock %}">There</li>
<li class="{% block nav_anywhere %}{% endblock %}">Anywhere</li>
</ul>

{% block content %}{% endblock %}

there.html

{% extends "base.html" %}
{% block nav_there %}active{% endblock %}
{% block content %}
<blockquote>No matter where you go, there you are.</blockquote>
{% endblock %}

The base navigation defines empty nav_ blocks in the li class and the sub template sets the relevant one to active. You can extend this as far as you want to have sub-navigation within pages too.

Dynamically setting active class with Flask and jinja2

The way the code appears in the editor is not causing any issues, but it could mean you don't a have a syntax/language support plugin/add-on installed.

If you're not getting any template errors (TemplateSyntaxError, for example), it could be that the data in navigation_bar or active_page simply don't match. Could you include the data for these?

Alternatively, my go to is to have active_page set on the base template and each page template:

{% set active_page = 'home' %}

and in navigation items I add:

<li class="other-styles {{'active' if active_page == 'the page' }}">

jinja2: Can I render template tags from an expression?

Other than {% include ... %} and {% extends ... %}, you're not going to be able to have the template system automatically render something that's added to a template during runtime without a bit of customization.

The beautiful part about Jinja 2 is that its API is very powerful and you can do many things without having to feel like your "hacking" the system. To do what your first example is implying, you just need to have the function render the included template snippet snd return a rendered string. If you're expecting the template to be rendered with the context of the parent template, that's not gonna happen automatically, but that's not a problem since you can pass in whatever you need directly in your function call in the template.

Flask raises TemplateNotFound error even though template file exists

You must create your template files in the correct location; in the templates subdirectory next to the python module (== the module where you create your Flask app).

The error indicates that there is no home.html file in the templates/ directory. Make sure you created that directory in the same directory as your python module, and that you did in fact put a home.html file in that subdirectory. If your app is a package, the templates folder should be created inside the package.

myproject/
app.py
templates/
home.html
myproject/
mypackage/
__init__.py
templates/
home.html

Alternatively, if you named your templates folder something other than templates and don't want to rename it to the default, you can tell Flask to use that other directory.

app = Flask(__name__, template_folder='template')  # still relative to module

You can ask Flask to explain how it tried to find a given template, by setting the EXPLAIN_TEMPLATE_LOADING option to True. For every template loaded, you'll get a report logged to the Flask app.logger, at level INFO.

This is what it looks like when a search is successful; in this example the foo/bar.html template extends the base.html template, so there are two searches:

[2019-06-15 16:03:39,197] INFO in debughelpers: Locating template "foo/bar.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/foo/bar.html')
[2019-06-15 16:03:39,203] INFO in debughelpers: Locating template "base.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/base.html')

Blueprints can register their own template directories too, but this is not a requirement if you are using blueprints to make it easier to split a larger project across logical units. The main Flask app template directory is always searched first even when using additional paths per blueprint.



Related Topics



Leave a reply



Submit