Wessi
Wessi

Reputation: 1812

Django: Highlight current page in navbar

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.

Upvotes: 16

Views: 10389

Answers (6)

Tim
Tim

Reputation: 639

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.

Upvotes: 1

theshubhagrwl
theshubhagrwl

Reputation: 1026

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.

Upvotes: 3

tombreit
tombreit

Reputation: 1379

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>

Upvotes: 4

Will Howell
Will Howell

Reputation: 3715

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 %}

Upvotes: 41

MicroPyramid
MicroPyramid

Reputation: 1630

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");
       });

Upvotes: 1

Paul Goodier
Paul Goodier

Reputation: 43

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/

Upvotes: 4

Related Questions