15

In my layout.html (sometimes called base.html) I have a navbar like this:

    <li class="dropdown"><a href="{% url 'index' %}" >Home </a></li>
    <li class="dropdown"><a href="{% url 'house_list' %}">Your houses</a></li>
    <li class="dropdown"><a href="{% url 'agency_list' %}">Agencies</a></li>
    <li class="dropdown"><a href="/admin">Admin</a></li>
    <li class="dropdown"><a href="{% url 'logout' %}"><i class="fa fa-lock"></i> Log ud</a></li>
    <li class="dropdown"><a href="{% url 'login' %}"><i class="fa fa-lock"></i> Log ind</a></li>

I would like to highlight the current page in the navbar which is done by changing <li class="dropdown"> to <li class="dropdown active">

Is there a way for Django to insert active for the page the user is on? Any help is much appreciated!

I'm using Django 1.9 and Python 3.5.

Wessi
  • 1,702
  • 4
  • 36
  • 69
  • 1
    Possible duplicate of [Django dynamically get view url and check if its the current page](http://stackoverflow.com/questions/22047251/django-dynamically-get-view-url-and-check-if-its-the-current-page) – Sayse Sep 22 '16 at 12:56

6 Answers6

38

You can get the name of the url (referenced in your urlpatterns). Then set the 'active' class if the url matches.

{% with url_name=request.resolver_match.url_name %}
<li class="dropdown {% if url_name == 'index' %}active{% endif %}"
   <a href="{% url 'index' %}" >Home </a>
</li>
<li>...</li>
{% endwith %}
Will Howell
  • 3,585
  • 2
  • 21
  • 32
4

I had a simialr question and found that using Djangos templates solved my issue. By creating a 'base' template containing the navbar, leaving the active flag to be populated by each page.

Like this:

base.html file containing this

<li {% block nav_index%}{% endblock %}><a href="{% url 'index' %}" >Home </a></li>
<li {% block nav_house_list%}{% endblock %}><a href="{% url 'house_list' %}">Your houses</a></li>
<li {% block nav_agency_list%}{% endblock %}><a href="{% url 'agency_list' %}">Agencies</a></li>
<li {% block nav_admin%}{% endblock %}><a href="/admin">Admin</a></li>
<li {% block nav_logout%}{% endblock %}><a href="{% url 'logout' %}"><i class="fa fa-lock"></i> Log ud</a></li>
<li {% block nav_login%}{% endblock %}><a href="{% url 'login' %}"><i class="fa fa-lock"></i> Log ind</a></li>

Then referencing that on each page. Inserting 'active' for each url:

{% extends "base.html" %}

{% block nav_index%}
    class="active"
{% endblock %}

(replace nav_index for each page)

Django has some good documentation on it: https://docs.djangoproject.com/en/1.7/topics/templates/

  • 1
    But that still require that you insert a unique tag in every template, right? Ideally you would want all the code in base.html. It's still a nice a simple solution though:) – Wessi Sep 22 '16 at 16:22
3

When not using a dedicated template tag for the menu generation, I set the active menu item class if the view_name of the current request matches the view_name of the linked item:

Pseudo code:

<a 
  class="{% if request.resolver_match.view_name == 'foo' %}active{% endif %}"
  href="{% url 'foo' %}"
>Foo</a>

Not very DRY, but when not dealing with a lot of navigation items it does the job:

<a class="nav-item nav-link {% if request.resolver_match.view_name == 'core:dashboard' %}active{% endif %}" href="{% url 'core:dashboard' %}">Dashboard</a>
<a class="nav-item nav-link {% if request.resolver_match.view_name == 'publications:index' %}active{% endif %}" href="{% url 'publications:index' %}">Publications</a>
tombreit
  • 1,199
  • 8
  • 27
3

I have a simple solution: In your views.py pass an additional parameter in your context dictionary

def home(request):
    return render(request, 'template_name', {'home_page': 'active'})

then in your base.html (where you have the navbar):

<li class="nav-item {{home_page}}">                
  <a class="nav-link" href="{% url 'home' %}">Home</a>
</li>

In this way whenever you will pass call the home function it will also send the 'home_page' which will make the current URL acitve.

Note that I am using bootstrap here.

theshubhagrwl
  • 743
  • 9
  • 17
1

You need to specify below script in your HTML file. Here we are retrieving current window anchor tag and then adding the active class to the respective <li> tag.

$(document).ready(function(e){
         var pathname = window.location.pathname;
         atag = $('.dropdown a[href="'+pathname+'"]'); #Here you should mention your <li> class name "dropdown"
         atag.parent().addClass("active");
       });
MicroPyramid
  • 1,570
  • 19
  • 22
0

I was running into the same issue with my code base(Django + bootstrap4). I didn't want to specify all the highlighted routes myself and wanted something which supports nested paths as well. The following solution uses vanilla JS with xpath selectors to search for all the nav-items and compare them with the document's location path.

let navItemsIter = document.evaluate('//li[@class="nav-item"]//a', document);
function getPathBase(path) {
    let pathBase = path.split('/').filter(function(e){return e})
    if(pathBase.length===0) return null;

    return pathBase[0];
}
try {
    const pathBase = getPathBase(document.location.pathname);
    var navNode = navItemsIter.iterateNext;

    while(navNode) {
        navNode = navItemsIter.iterateNext();
        if(pathBase===getPathBase(navNode.attributes.href.nodeValue)) {
            navNode.attributes.class.nodeValue = navNode.attributes.class.nodeValue+' active'
            break;
        }
    }
} catch(err) {
    console.log('Error: Document tree modified during iteration', err)
}

You might need to change the xpath selector based on your html's structure.

Tim
  • 599
  • 5
  • 15