skip to Main Content

I’m implementing a Django forum app, it has a navigation bar. It is styled to display a chosen page of the site with "active" style (like, a brighter button), and others – as "inactive" (colored as usual).

As in normal template layout, I have a basic template, ‘base.html’, where the header with current time, authorization bar and navigation bar should be included, and {% block content %} left for other templates that inherit the basic template.

But I don’t know how to implement the switching of "active/inactive" style of the navigation bar’s buttons, so as for now I handle it with a separate navbar for every template, which violates DRY principle AS HELL:

base.html (pretty useless, as the same code is included in every other template of the site):

{% load static %}

<!DOCTYPE html>
<html>
<head>
    <link type="text/css" href="{% static 'css/styles.css' %}" rel="stylesheet"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>{{title}}</title>
</head>
<body id="third">
    <header>
        {% include 'inc/_timedate.html' %}
        {% include 'inc/auth.html' %}
        <nav class="navbar">
            <a class="btn active" href="{% url 'home' %}">Home</a>
            <a class="btn" href="{% url 'about' %}">About</a>
            <a class="btn" href="{% url 'characters' %}">Characters</a>
            <a class="btn" href="{% url 'episodes' %}">Episodes</a>
            <a class="btn" href="{% url 'forum:forum' %}">Forum</a>
        </nav>
    </header>

{% block content %}
{% endblock %}

{% block pagination %}
{% endblock %}

</body>
</html>

So, as you can see, the button displayed with the "active" style is the homepage button (style btn active). AFAIC, the navbar can be put into includes’ folder and to be added to templates via {% include ” %}, as I did with "timedate.html" and "auth.html". But for that sake I need a solution (maybe, a script) that changes the style of navbar buttons depending on their chosen status by user.

I’ve googled for such scripts (I’m zero in JS, I can understand its logic and syntax, as it is pretty similar to C, but not to reproduce it), and found one that seems to do the trick (I put it right after <nav></nav> section, in the end of the <header> section):

        <script>
            var header = document.getElementByClassName("navbar");
            var btns = header.getElementsByClassName("btn");
            for (var i = 0; i < btns.length; i++) {
                btns[i].addEventListener("click", function() {
                    var current = document.getElementsByClassName("active");
                    current[0].className = current[0].className.replace(" active", "");
                    this.className += " active";
                });
            }
        </script>

but it doesn’t, unfortunately.

Can you give me an advice/hint/solution?

styles.css (if necessary):

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* Конец сброса CSS */

#current-date {
  color: #FFFFFF;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
}
.navbar {
  width: 700px;
  height: 20px;
  padding: 10px 12px 15px 0;
  margin: 0 0 10px 0;
  overflow: hidden;
  background-color: #1B182B;
}
.navbar .btn {
  float: left;
  color: #f2f2f2;
  text-align: center;
  padding: 10px 12px 10px 12px;
  text-decoration: none;
  font-size: 17px;
  font-weight: 500;
  background-image: radial-gradient(rgba(83, 50, 128, .84), rgba(71, 11, 150, .84) 80%);
}
.navbar .btn:hover {
  background-color: yellow;
  color: #1B182B;
}
.navbar .btn.active {
  background: #5214b8;
  color: white;
  cursor: pointer;
}
.navbar .btn.inactive {
  background: #462f6b;
  color: grey;
  cursor: default;
}
<and others for other needs>

2

Answers


  1. Since the nav items are <a> tags, and navigate away from the current screen anyway, I would probably solve this on the server side. I’m not familiar with django, but I think a hash table could work here.

    # In your Django view or model
    navigation_active_class = {}
    
    # Adding key-value pairs
    #initialize all to empty string
    navigation_active_class['home'] = ''
    navigation_active_class['about'] = ''
    navigation_active_class['characters'] = ''
    navigation_active_class['episodes'] = ''
    navigation_active_class['forum'] = ''
    
    #* psuedo-code; I don't know how to do this in django *
    #get the url, maybe
    full_url = request.build_absolute_uri()
    #somehow match up the url with the home, about, etc keys.
    # then set the appropriate navigation_active_class item to "active"
    navigation_active_class[appropriate_key_from_prev_step] = 'active'
    
    #display the nav
    <nav class="navbar">
          <a class="btn {% navigation_active_class.get('home')%}" href="{% url 'home' %}">Home</a>
          <a class="btn {% navigation_active_class.get('about')%}" href="{% url 'about' %}">About</a>
          <a class="btn {% navigation_active_class.get('characters')%}" href="{% url 'characters' %}">Characters</a>
          <a class="btn {% navigation_active_class.get('episodes')%}" href="{% url 'episodes' %}">Episodes</a>
          <a class="btn {% navigation_active_class.get('forum')%}" href="{% url 'forum:forum' %}">Forum</a>
    </nav>
    
    Login or Signup to reply.
  2. If you insist on using javascript, it’s still pointless to add the class to the anchor tag right before you navigate away. So you’d need to run it on page load

    const header = document.getElementsByClassName("navbar")[0];
    const btns = header.getElementsByClassName("btn");
    
    //use window.location.href, etc to get the current url instead of hardcoding
    const currentURL = "mysite.com/episodes";
    document.querySelector(`a.btn[href="${currentURL}"]`).classList.add("active");
    html, body, div, span, applet, object, iframe,
    h1, h2, h3, h4, h5, h6, p, blockquote, pre,
    a, abbr, acronym, address, big, cite, code,
    del, dfn, em, img, ins, kbd, q, s, samp,
    small, strike, strong, sub, sup, tt, var,
    b, u, i, center,
    dl, dt, dd, ol, ul, li,
    fieldset, form, label, legend,
    table, caption, tbody, tfoot, thead, tr, th, td,
    article, aside, canvas, details, embed,
    figure, figcaption, footer, header, hgroup,
    menu, nav, output, ruby, section, summary,
    time, mark, audio, video {
      margin: 0;
      padding: 0;
      border: 0;
      font-size: 100%;
      font: inherit;
      vertical-align: baseline;
    }
    /* HTML5 display-role reset for older browsers */
    article, aside, details, figcaption, figure,
    footer, header, hgroup, menu, nav, section {
      display: block;
    }
    body {
      line-height: 1;
    }
    ol, ul {
      list-style: none;
    }
    blockquote, q {
      quotes: none;
    }
    blockquote:before, blockquote:after,
    q:before, q:after {
      content: '';
      content: none;
    }
    table {
      border-collapse: collapse;
      border-spacing: 0;
    }
    
    /* Конец сброса CSS */
    
    #current-date {
      color: #FFFFFF;
      font-size: 14px;
      font-weight: 500;
      line-height: 20px;
    }
    .navbar {
      width: 700px;
      height: 20px;
      padding: 10px 12px 15px 0;
      margin: 0 0 10px 0;
      overflow: hidden;
      background-color: #1B182B;
    }
    .navbar .btn {
      float: left;
      color: #f2f2f2;
      text-align: center;
      padding: 10px 12px 10px 12px;
      text-decoration: none;
      font-size: 17px;
      font-weight: 500;
      background-image: radial-gradient(rgba(83, 50, 128, .84), rgba(71, 11, 150, .84) 80%);
    }
    .navbar .btn:hover {
      background-color: yellow;
      color: #1B182B;
    }
    .navbar .btn.active {
      background: #5214b8;
      color: white;
      cursor: pointer;
    }
    .navbar .btn.inactive {
      background: #462f6b;
      color: grey;
      cursor: default;
    }
      <header>
            <nav class="navbar">
                <a class="btn" href="mysite.com/home">Home</a>
                <a class="btn" href="mysite.com/about">About</a>
                <a class="btn" href="mysite.com/characters">Characters</a>
                <a class="btn" href="mysite.com/episodes">Episodes</a>
                <a class="btn" href="mysite.com/forum">Forum</a>
            </nav>
        </header>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search