I started studying Flask with a site rework, where all pages are static. Now all page templates will be inherited from the main base template, which has the main menu of the site:

... <ul class="nav navbar-nav"> <li> <a href="{{ url_for('main.index') }}">Главная</a> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Услуги<b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="{{ url_for('main.projects_development') }}">Проекты освоения</a></li> <li class="divider"></li> <li><a href="{{ url_for('main.forest_regulation') }}">Лесоустройство</a></li> </ul> </li> <li> <a href="{{ url_for('main.contacts') }}">Контакты</a> </li> <li> <a href="{{ url_for('main.about_us') }}">О нас</a> </li> <li><a href="#">Вход</a></li> </ul> 

I faced the problem of selecting the menu item that corresponds to the active page; earlier the active class was added manually in the code itself, now it is necessary to define this class dynamically. So far, from ideas there is only the addition of an if block, which checks the entry of a string with a route into the value of request.url, that is, something like this:

 <li {% if '/contacts' in request.url %}class="active"{% endif %}> 

Tell me, please, how to implement it correctly? How to check this condition for the route '/'? Or, in general, is it more correct to implement through JS?

    3 answers 3

    The variable request is available in the templates and contains the corresponding Request object . And in this object, request.endpoint and request.view_args are available, which contain complete information about which view is currently working and with which arguments, and you can write something like {% if request.endpoint == 'index' %}active{% endif %} , thus not being tied to specific links and not clinging to unnecessary variables.

    Since the checks will almost certainly be long, it makes sense to put all of the same type into a macro, or even into a separate function, which then zaphnut in the context of Jinja2 . In one of my projects I use this function:

     from flask import request def is_current_endpoint(endpoint, **kwargs): if not endpoint or endpoint != request.endpoint: # проверяем, та ли вьюха return False if kwargs and not request.view_args: # если переданы аргументы, проверяем и их return False for k in kwargs: if k not in request.view_args or request.view_args[k] != kwargs[k]: return False return True 

    It is used like this (it is advisable to render in a macro):

     <li class="menu{% if is_current_endpoint('index') %} active{% endif %}"> Главная </li> <li class="menu{% if is_current_endpoint('posts_index') %} active{% endif %}"> Посты </li> {% if current_user.is_authenticated %}{# Объект из Flask-Login для примера #} <li class="menu{% if is_current_endpoint('profile', username=current_user.username) %} active{% endif %}"> Мой профиль </li> {% endif %} <li class="menu{% if is_current_endpoint('profile', username='admin') %} active{% endif %}"> Профиль админа :) </li> 

      I solved the problem this way (maybe someone will come in handy, someone will suggest another option or correct it):

      base.html

       <ul class="nav navbar-nav"> <li {% block index %}{% endblock %}> <a href="{{ url_for('main.index') }}"> Главная </a> </li> <li class="dropdown {% block services %}{% endblock %}"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Услуги<b class="caret"></b> </a> <ul class="dropdown-menu"> <li> <a href="{{ url_for('main.projects_development') }}">Проекты освоения</a> </li> <li class="divider"></li> <li><a href="{{ url_for('main.forest_regulation') }}">Лесоустройство</a></li> </ul> </li> <li {% block contacts %}{% endblock %}> <a href="{{ url_for('main.contacts') }}"> Контакты </a> </li> <li {% block about_us %}{% endblock %}> <a href="{{ url_for('main.about_us') }}">О нас</a> </li> {% if current_user.is_authenticated %} <li><a href="{{ url_for('auth.logout') }}">Выход</a></li> {% else %} <li><a href="{{ url_for('auth.login') }}">Вход</a></li> {% endif %} </ul> 

      index.html

       {%- extends 'base.html' %} ... {% block index %}class="active"{% endblock %} 

      contacts.html

       {%- extends 'base.html' %} ... {% block contacts %}class="active"{% endblock %} 

      and so on in all pages that correspond to the main menu items of the site

        I set some template variable in the view, and check it in the template itself:

         <a class="{%if curr_page == "about"%}active{% endif %}">About</a> 

        To simplify the perception, the construction can be crammed into a macro:

         {% macro is_active(label) %} {% if label == curr_page %} active {% else %} passive {% endif %} {% endmacro %} 

        And in the link:

         <a class="{{is_active('about')}}">About</a> 

        This allows you to manage the selection of menu items. For me it is more convenient than directly linking to the addresses of the pages.

        • Thank you very much for another option) - Stright