Reputation: 699
In a Django app, a lot of class-based views are called directly from the urls.py like so
url(r'^manage/thing/$',
ListView.as_view(model=Thing,
queryset=Thing.objects.filter(parent=None)),
name='mg_thing_list'),
and most CBVs are not subclassed, so views.py is almost empty. I want to highlight the active section in the navbar based on the URL. For example, pages at /manage/thing/...
should have class="active"
next to the "thing" item in the navbar HTML. What's the DRYest way of doing this?
I want to avoid subclassing the CBVs just to add the request to the template context (which the standard templatetag solution seems to require). Currently we do it in a dumb way: add a {% block %}
for every navbar item tag and set the relevant block to class="active"
in each and every template. Seems a waste.
Upvotes: 1
Views: 1510
Reputation: 393
You can use this snippet to add active
class to your html code. It does a reverse resolve based on the url name
parameter.
In your_app/templatetags/base_utils.py
from django import template
from django.core import urlresolvers
register = template.Library()
@register.simple_tag(takes_context=True)
def current(context, url_name, return_value=' active', **kwargs):
matches = current_url_equals(context, url_name, **kwargs)
return return_value if matches else ''
def current_url_equals(context, url_name, **kwargs):
resolved = False
try:
resolved = urlresolvers.resolve(context.get('request').path)
except:
pass
matches = resolved and resolved.url_name == url_name
if matches and kwargs:
for key in kwargs:
kwarg = kwargs.get(key)
resolved_kwarg = resolved.kwargs.get(key)
if kwarg:
# for the comparison of same type url arg d+ w+
kwarg = unicode(kwarg)
if not resolved_kwarg or kwarg != resolved_kwarg:
return False
return matches
In your_template.html
{% load base_utils %}
<li class="{% current 'your_url_name' param1=param1 param_N=param_N %}"><a href="{% url 'your_url_name' param1=param1 param_N=param_N %}"> This is NavBar Button </a></li>
Upvotes: 2
Reputation: 649
First of all, it's not recommended to hold logic in urls.py, also there are 2 ways to go about your issue here
First a template context processor: (in myapp/context_processors.py)
def mytag(request):
context = {'class': 'active'}
return context
Then
<div class='{{ class }}'>
Finally add the template context processor to TEMPLATE_CONTEXT_PROCESSORS in settings.py or in Django 1.8
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['components/templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'myapp.context_processors.mytag',
],
},
},
Also, just as a very common opinion on views, you should keep view logic in views, that way if you needed to build some mixins you could. Keep urls small.
Upvotes: 2
Reputation: 4848
I have had the question if I understand you correctly, and I solved it by using jQuery
like this:
function mainNavListAddClass() {
var theA = $("a[href=" + "'" + getCurrentUrlPath() + "'" + "]");
if (theA.length) {
theA.first().addClass("active");
}
}
function getCurrentUrlPath() {
return location.pathname;
}
Upvotes: 0