skip to Main Content

I have a problem enabling the .active class for each menu item I click in the navbar of my website (which is built in HTML, CSS, JS).
I use a file nav.html to load the navbar in all my pages, with this code:

<header id="hero-header">
               <script>        AOS.init();
            </script>
    <div class="logo-container">
        <a href="home.html"><img class="logo-desktop" id="logo-hero" src="assets/img/logo.svg"></a>
        <a href="home.html"><img class="logo-mobile" id="logo-hero" src="assets/img/mobile-logo.svg"></a>
    </div>

    <ul>
        
        <li data-aos="fade-down" data-aos-duration="600"><a href="home.html" class="menu-item-desktop">Home</a></li>
        <!-- <li data-aos="fade-down" data-aos-duration="600"><a href="map.html" class="">Map</a></li> -->
        <div data-aos="fade-down" data-aos-duration="800" class="menu-item-desktop dropdown">
            <button class="dropbtn">LifePulse ID</button>
            <div class="dropdown-content">
                <a href="before-donation.html">Before Donation</a>
                <a href="after-donation.html">After Donation</a>
                <a href="how-else-can-I-help.html" class="">How else can I help</a>
            </div>
        </div>                    
        <li data-aos="fade-down" data-aos-duration="1000"><a href="team.html" class="menu-item-desktop">Team</a></li> 
        <li data-aos="fade-down" data-aos-duration="1000"><a href="news.html" class="menu-item-desktop ">News</a></li>
        <li data-aos="fade-down" data-aos-duration="1200"><a href="partners.html" class="menu-item-desktop ">Partners</a></li> 
        <li data-aos="fade-down" data-aos-duration="1400"><a href="contact.html" class="menu-item-desktop ">Contact</a></li>
        
        <div data-aos="fade-down" data-aos-duration="1600" class="search-button">
            <form action="/search">
                <input type="search" name="q" id="search" placeholder="Type and click enter">
                <a href="#" id="btn-close">
                    <span class="fontawesome-close">
                        <i class="fa-solid fa-times" style="color: #ffffff;"></i>
                    </span>
                </a>
                <a href="#" id="btn-search">
                    <span class="fontawesome-search">
                        <i class="fa-solid fa-magnifying-glass" style="color: #ffffff;"></i>
                    </span>
                </a>
            </form>
        </div>
    </ul>
    <div class="button-container">
        <a href="contact.html">
            <div class="magnetic">
                <div class="wrap">
                    <div class="span span-1 go"></div>
                    <div class="span span-2 go"></div>
                    <div class="span span-3 go"></div>
                    <div class="span span-4 go"></div>
                    <div class="span span-1 go"></div>
                    <img src="assets/img/hand.png">
                </div>
            </div>
        </a>
    </div>
</header> 

<div id="hero-bottom">
    <div class="city">Thessaloniki, GR</div>
    <ul>
        <a href="https://www.instagram.com/lifepulse_gr" target="_blank"><li><i class="fa-brands fa-instagram " style="color: #ffffff;"></i></li></a>
        <a href="https://www.facebook.com/lifepulsegreece"  target="_blank"><li><i class=" fa-brands fa-facebook-f social-icons fa-s" style="color: #ffffff;"></i></li></a>
        <a href="https://www.linkedin.com/company/lifepulse-blood-donation"  target="_blank"><li><i class="fa-brands fa-linkedin-in" style="color: #ffffff;"></i></li></a>       
    </ul>
</div>

I want each time I click on a menu item, this specific item to jump on active state. I tried creating a file menus.js with this code:

const links =document.querySelectorAll(".menu-item-desktop ");
links.forEach(btn => btn.addEventListener("click",(e)=>{
     e.preventDefault();
     btn.classList.add("active")
  }));

and adding it at the bottom of the body tag in every html page, but it didn’t work. What am I missing?

2

Answers


  1. If you want to click on links that replaces the page you are on with another page AND have the nav items to be active? Then you need to store what has been clicked in localStorage.

    Alternatively load the HTML pages from the links using the same .load method you use for the nav.html

    If not, then use delegation because that is a simpler way

    You need to delegate from the nearest STATIC container- the one you load the nav into

    Also since you load the nav menu using .load, you need the script that handles the clicks to NOT be in that file since JS will not run in an HTML page loaded using AJAX (which .load is).

    This code needs to live in the page you load (external script is fine) and not in nav.html

    Here is a jQuery version which will load the nav AND delegate

    https://jsfiddle.net/x6ourewL/1/

    $(() => { // page loading
      const activeURL = localStorage.getItem('activeURL');
      const $container = $('#nav-placeholder')
      .load('nav.html', function() {
        // AOS.init(); // if that is needed in the nav
        $links = $('.menu-item-desktop a');
        console.log(activeURL, $(`[href="${activeURL}"]`).attr('href'))
        $link = activeURL ? $(`[href="${activeURL}"]`).eq(0) : $links.eq(0);
        $link.addClass('active'); // activate the first or first of found link (if that makes sense)
      }) 
      .on('click', '.menu-item-desktop a', function() { // delegation
        localStorage.setItem('activeURL',$(this).attr('href')); // before the link loads the new page
      });
    });
    
    Login or Signup to reply.
  2. Your issue is that the event handler code is running before the elements have loaded and thus does not add any events.

    You have a number of options:

    • add the code to .load complete callback
    • use event delegation (see this answer (or the simpler jquery answer on that question as using jquery)

    Putting your event handler code inside document load / doc.ready would not work as that would fire before your secondary load.

    As provided in the comments, your code is currently (I’m assuming the event code is in the doc.ready, makes no difference)

    $(function(){ 
        $("#nav-placeholder").load("nav.html"); 
    
        const links = document.querySelectorAll(".menu-item-desktop");
        links.forEach(btn => btn.addEventListener("click",(e)=>{
           e.preventDefault();
           btn.classList.add("active")
        }));
    });
    

    Change this to add the event code inside the load callback:

    $("#nav-placeholder").load("nav.html", function() {
    
        const links = document.querySelectorAll(".menu-item-desktop");
        links.forEach(btn => btn.addEventListener("click",(e)=>{
           e.preventDefault();
           btn.classList.add("active")
        }));
    });
    
    

    Event delegation would be, using jquery as you’ve used jquery for doc/ready and load:

    $(function(){ 
        $("#nav-placeholder").load("nav.html"); 
    
        $(document).on("click", ".menu-item-desktop", function(e) {
           e.preventDefault();
           $(".active").removeClass("active");
           $(this).addClass("active");
        });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search