4

THE AIM

I have the code below with a bottom navbar of three different menus showing three different contents in which I would like the following to happen:

  1. The default active menu/content should be the first one (home menu).
  2. One menu/content should always be active, i.e. if I click on the current menu nothing would happen and only if I click on a different one I would see some change (i.e. other menu and content would be active).
  3. When refreshing the page, the user should remain in the menu/content they were before refreshing with the menu icon active (i.e. black) and the content of the respective menu shown.
  4. When closing the browser/tab and reopening, the menu/content shown should be the default one (home menu).

THE PROBLEM

Once first opened the browser/tab the default menu/content (home) is shown as desired. However, when clicking in another menu icon, only it's icon menu is shown as active and the content does not shows at all, I think this is because I am using $(this) and it only represents a[class^=menu].

When refreshing, the content of the menu is shown as active but the menu icon is not (i.e. it is not black). As I keep clicking on other menus, their menu icons are shown as active but their respective contents are not shown at all.

THE ATTEMPT

By the doing the following I obviously got contents overlapping...

$("div[class^=content]").addClass("active");

It is not clear to me how I can make a proper use of $(this) to also target the respective content of the current menu.

SUMMARY

  1. Set the content of the respective menu active when such menu is also active.
  2. When refreshing the browser, both the menu and content should be active (i.e. menu icon is black and the content of the respective menu is shown).

      $(document).ready(function() {

        $("a[class^=menu]").click(function() {

          if ($("a[class^=menu],div[class^=content]").hasClass("active")) {
            $("a[class^=menu],div[class^=content]").removeClass("active");
          }

          var href = $(this).attr("href");

          $(this).addClass("active");
          $(href).addClass("active");

        });

        if (window.location.hash.substr(1) != "") {
          $("a[class^=menu],div[class^=content]").removeClass("active");
          $('a[href="' + window.location.hash.substr(1) + '"]').addClass("active");
          $("#" + window.location.hash.substr(1)).addClass("active");
        }

      });
.container {
      margin: 0 auto;
      background-color: #eee;
      border: 1px solid lightgrey;
      width: 20vw;
      height: 90vh;
      font-family: sans-serif;
      position: relative;
    }

    header {
      background-color: lightgreen;
      padding: 5px;
      text-align: center;
      text-transform: uppercase;
    }

    .bottom-navbar {
      position: absolute;
      bottom: 0;
      width: 100%;
      padding: 6px 0;
      overflow: hidden;
      background-color: lightgreen;
      border-top: 1px solid var(--color-grey-dark-3);
      z-index: 50;
      display: flex;
      justify-content: space-between;
    }

    .bottom-navbar>a {
      display: block;
      color: green;
      text-align: center;
      text-decoration: none;
      font-size: 20px;
      padding: 0 10px;
    }

    .bottom-navbar>a.active {
      color: black;
    }

    .menu-1.active,
    .menu-2.active,
    .menu-3.active {
      color: black;
    }

    .content-1,
    .content-2,
    .content-3 {
      display: none;
    }

    .content-1.active,
    .content-2.active,
    .content-3.active {
      display: block;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translateX(-50%) translateY(-50%);
    }
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

 
 <div class="container">
    <header>My header</header>
    <div class="main-content">
      <div class="content-1 active" id="firstPage">House content</div>
      <div class="content-2" id="secondPage">Map content</div>
      <div class="content-3" id="thirdPage">Explore content</div>
      <div class="bottom-navbar">
        <a href="mywebsite#firstPage" class="menu-1 active"><i class="fa fa-home"></i></a>
        <a href="mywebsite#secondPage" class="menu-2"><i class="fa fa-map"></i></a>
        <a href="mywebsite#thirdPage" class="menu-3"><i class="fa fa-search"></i></a>
      </div>
    </div>

UPDATE

The URL solution is essentially answered in the link below, although the suggestions in the comments helped tremendously in solving most of the problem before the browser was refreshed.

Selecting the anchor tag of a particular href using jQuery

Joehat
  • 979
  • 1
  • 9
  • 36

1 Answers1

1

As the buttons aren’t separated in a way that allows them to affect visibility of the content, you’ll need to explicitly address the particular element whose visibility you want to show. I’d suggesting inspecting the class of the menu item referenced by $(this) and following it by a conditional branch that handles the case for each of menu-1, menu-2, and menu-3, referencing their respective contents to set them active, e.g., $(‘.content-1’).addClass(‘active’)

As for persistence, you can store a variable that keeps track of what item is currently active and then activate that on page load through conditionals. Give this a read to see how to store that info: https://stackoverflow.com/a/16206342/12380239

  • I had something like that before, but I found myself being repetitive. Is there a way you would recommend to avoid repetition and obtain the same result? This is what I had before without the URL# part https://codepen.io/fergos2/pen/vYYaRzN?editors=1010 – Joehat Dec 02 '19 at 11:02
  • Personally, I’m not sure of any way to do so. I’m under the impression that part of why people use frontend libraries, eg Bootstrap, is to try to avoid the need to show this sort of repetition. That way the library handles the ugly bits and you can focus on the layout and contents and such. (PS, rather than using the conditionals to check if the others are active, you can just deactivate everything and activate the one you want - that will look a bit cleaner and should achieve the same functionality) – Saahil Hamayun Dec 02 '19 at 11:10
  • 1
    Something along the lines of this: https://gist.github.com/saahilh/c1c0dcc17fbe23266eda09d4448d82a8#file-gistfile1-txt – Saahil Hamayun Dec 02 '19 at 11:32
  • If you do find that it leads to an annoying issue where the clicking load for the content pane that’s already active causes that pane to reload, and that is undesirable (and it may still be desirable, eg for consistency’s sake), then maybe more complicated conditions can be order, for example those you have in use now. – Saahil Hamayun Dec 02 '19 at 11:34
  • as I said on the update part of the question (after editing) your suggestion helped solving most of the problem. However, the only remaining issue is the line $('a[href="' + window.location.hash.substr(1) + '"]').addClass("active"); and I was wondering if you had another suggestion for this... – Joehat Dec 04 '19 at 11:49
  • So what I was thinking is more along the lines of creating a variable called activeClassName or some such in sessionStorage, and then on page load, reading that and setting the active pane. If you don’t attach it to a listener, which in this case is to say if you move it outside that jQuery listener you have, then it should only execute the one time, on the initial page render. (Depending on how you approach it, you might even be able to make those if statements into a method) – Saahil Hamayun Dec 04 '19 at 18:48
  • Ah I see. You want to maintain that information in the URL. In that case what I’ve said above, about moving it outside the listener, is still applicable. That’s your issue here then, if it’s not happening on page load. You also need to be modifying the URL appropriately in your code to contain whatever information you’ll need, in case that’s not something you’ve done. – Saahil Hamayun Dec 04 '19 at 18:51