Dropdown menus integrated into a responsive navigation bar

The issue: When in responsive view, the dropdown button does not transition to the visible navigation bar from the menu icon after clicking any of its dropdown content.

More details: In responsive view (screen width below 730px), the navigation bar is replaced by a menu icon. The desired behavior is for any <a> or dropdown <button> to shift to the visible navigation bar upon clicking any dropdown item.

https://i.sstatic.net/iV2TEMhj.png

You can find the code at https://codepen.io/Balazs-Keisz/pen/KKOmgQX

Below is the JavaScript responsible for managing the navigation bar:

    // Function to toggle responsive class for topnav when icon is clicked
    function myFunctionIcon() {
      var x = document.getElementById("myTopnav");
      if (x.className === "topnav") {
        x.className += " responsive";
      } else {
        x.className = "topnav";
      }
    }
    
    // Function to clear all highlights
    function clearAllHighlights() {
      // Remove highlight from all nav items and buttons
      document.querySelectorAll('.nav-item, .dropbtn').forEach(item => {
        item.classList.remove('highlight-menu');
      });
    }
    
    // Function to highlight the clicked button or link
    function highlightButton(clickedElement) {
      clearAllHighlights(); // Clear previous highlights
      clickedElement.classList.add('highlight-menu'); // Highlight the clicked element
      
      
    // If the clicked element is part of a dropdown, ensure only the dropdown button is highlighted
      const dropdownButton = clickedElement.closest('.dropdown')?.querySelector('.dropbtn');
      if (dropdownButton) {
        dropdownButton.classList.add('highlight-menu'); // Highlight only the dropdown button
      }
    }
    
    // Event listeners for nav items and dropbtns
    document.querySelectorAll('.nav-item, .dropbtn').forEach(item => {
      item.addEventListener('click', function(event) {
        highlightButton(this); // Apply highlight
        // Prevent closing the menu when clicking the dropdown button
        if (this.classList.contains('dropbtn')) {
          event.stopPropagation(); // Prevent event from bubbling up
        }
      });
    });
    
    // Event listener for each dropdown content link to close responsive menu
    document.querySelectorAll('.dropdown-content a').forEach(link => {
      link.addEventListener('click', function(event) {
        const dropdownButton = this.closest('.dropdown').querySelector('.dropbtn');
        highlightButton(dropdownButton); // Highlight only the dropdown button
        if (window.innerWidth <= 729) {
          document.getElementById("myTopnav").classList.remove("responsive"); // Close responsive menu
        }
      });
    });
    
    // Event listener for any other responsive <a> links to close the menu
    document.querySelectorAll('.nav-item').forEach(link => {
      link.addEventListener('click', function() {
        if (window.innerWidth <= 729) {
          document.getElementById("myTopnav").classList.remove("responsive"); // Close responsive menu
        }
      });
    });
    
    // Dropdown toggle function for multiple dropdowns
    function toggleDropdown1(dropdownId) {
      var dropdown = document.getElementById(dropdownId);
      dropdown.classList.toggle("show1");
    }
    
    // Function to close all dropdowns
    function closeAllDropdowns() {
      var dropdowns = document.getElementsByClassName("dropdown-content");
      for (var i = 0; i < dropdowns.length; i++) {
        dropdowns[i].classList.remove('show1');
      }
    }

    // Toggle dropdown for the clicked dropdown button
    function toggleDropdown1(dropdownContent) {
      // Check if the clicked dropdown is already open
      var isOpen = dropdownContent.classList.contains('show1');
      
      // Close all dropdowns
      closeAllDropdowns();

      // If the clicked dropdown was not open, open it
      if (!isOpen) {
        dropdownContent.classList.add('show1');
      }
    }

    // Add event listeners for each dropdown button
    document.querySelectorAll('.dropbtn').forEach(button => {
      button.addEventListener('click', function(event) {
        // Prevent closing on the same dropdown click
        event.stopPropagation();

        // Get the corresponding dropdown content
        var dropdownContent = this.nextElementSibling;

        // Toggle the dropdown
        toggleDropdown1(dropdownContent);
      });
    });

    // Close the dropdown if the user clicks outside of any dropdown
    window.addEventListener('click', function(event) {
      if (!event.target.matches('.dropbtn') && !event.target.matches('.dropbtn i')) {
        closeAllDropdowns();
      }
    });

    // Attach event listeners to all <a> and <button> elements for highlighting
    document.querySelectorAll('.nav-item, .dropbtn').forEach(item => {
      item.addEventListener('click', function() {
        highlightButton(this); // Highlight the clicked element
      });
    });

Answer №1

The issue lies with this specific section

// Event listener for each dropdown content link to close responsive menu
document.querySelectorAll('.dropdown-content a').forEach(link => {
    link.addEventListener('click', function (event) {
        const dropdownButton = this.closest('.dropdown').querySelector('.dropbtn');

Your selection is incorrect

.querySelector('.dropbtn');

as it targets a child of the relevant dropdown.

You cannot display a child if its parent is hidden!

To resolve this, remove the last .querySelector('.dropbtn') and you'll be all set.

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <link href='https://fonts.googleapis.com/css?family=Noto Serif' rel='stylesheet'>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <style>
        /* CSS styling goes here */
    </style>

    <div class="topnav" id="myTopnav">

        <!-- Additional code added -->
        <!-- Menu icon for mobile view -->
        <a href="javascript:void(0);" class="icon" onclick="myFunctionIcon()">&#9776;</a>

        <!-- Navigation items (links and buttons) -->
        <div class="dropdown">
            <!-- Dropdown button for 'Intro' -->
            <button onclick="highlightButton(this)" class="dropbtn">Intro
                <i class="fa fa-caret-down"></i>
            </button>
            <div id="myDropdown1" class="dropdown-content">
                <a href="#" onclick="document.getElementById('tab1').click();">Creator's Note</a>
                <a href="#" onclick="document.getElementById('tab2').click();">Fan Note</a>
            </div>
        </div>
        <a href="#cards" id='cards' class="nav-item">Cards</a>

        <div class="dropdown">
            <!-- Dropdown button for 'Rules' -->
            <button onclick="highlightButton(this)" class="dropbtn">Rules
                <i class="fa fa-caret-down"></i>
            </button>
            <div id="myDropdown2" class="dropdown-content">
                <a href="#" onclick="document.getElementById('tab3').click();">Table of Contents</a>
                <a href="#" onclick="document.getElementById('tab4').click();">Diagrams</a>
                <a href="#" onclick="document.getElementById('tab5').click();">Rule Book Viewer</a>
            </div>
        </div>
        <a href="#strategies" id='strategies' class="nav-item">Strategies</a>
        <a href="#resources" id='resources' class="nav-item">Resources</a>
        <a href="#about" id='about' class="nav-item">About</a>
        <a href="#contact" id='contact' class="nav-item">Contact</a>
    </div>
</head>
<script>
    // JavaScript functions go here
</script>
</body>

</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Improving file reading and parsing efficiency with fast random access using csv-parse in Node.js

I recently encountered a challenge while working with the csv-parser library in node for parsing large CSV files. The files I work with can range from 50,000 to 500,000 lines or even larger. My task involved performing computations on this data and then su ...

Is it possible to utilize Bootstrap 4 with Sass instead of SCSS in web development?

Just added Bootstrap 4 to my Rails 6 application and realized that all the files are in .SCSS format. Any way to switch Bootstrap to using Sass? I prefer using Sass because it's more streamlined without having to deal with brackets and semicolons... ...

Contrast in functionality between a pair of variables within a controller

Could you please clarify the distinction between two variables a1 and a2: app.controller("someCtrl",function(){ this.a1=somevalue; var a2=somevalue; }); Also, can you explain the lifespan of variable a2? ...

Implement a loading animation that will be displayed until a specific JavaScript code has finished loading

I need to implement a loading animation for an external JavaScript src while it's being loaded: <script src="https://xxxx.domain.com/xxx.js" type="text/javascript"></script> Currently, I am using jQuery (window).load, but it waits until ...

Yarn is incapable of locating node modules

It has been some time since I last used yarn / npm, and now I am facing an issue while trying to configure a basic express server with yarn and typescript. The problem is that yarn is not properly "linking" my node_modules directory. I suspect that I may ...

Issues with MySQL not functioning properly when using Promise.All in a Node.js environment

When it comes to running multiple mysql queries asynchronously in express node.js, MySQL works well with simple callbacks. However, I wanted to take it a step further by using async await with promise.all. I also experimented with promise.allSettled, but u ...

Error: The function Object.entries is not defined

Why does this error persist every time I attempt to start my Node.js/Express server? Does this issue relate to the latest ES7 standards? What requirements must be met in order to run an application utilizing these advanced functionalities? ...

Encountering difficulties in sending the data to Firebase through the contact form

import React, { useState } from 'react' import styled from 'styled-components' import Title from '../Components/Title' import { InnerLayout, MainLayout } from '../Styles/Layout' import ...

Customize the font color in Material UI to make it uniquely yours

How can I customize the default Text Color in my Material UI Theme? Using primary, secondary, and error settings are effective const styles = { a: 'red', b: 'green', ... }; createMuiTheme({ palette: { primary: { ...

What is the best approach for scaling @material-ui Skeleton in a grid row with variable heights?

I am working on creating a grid of Avatar images with a transition state where I want to show a skeleton representation of the image. To achieve this, I am using @material-ui/lab/Skeleton. The issue I'm facing is that since my images are set to autos ...

Making changes to the res object in an Express.js application

I came up with an innovative idea for the backend design of my single-page application website. My plan is to configure it so that any routes starting with "/api/" will return only the necessary data in JSON format, while all other routes will trigger a fu ...

Adjust Navbar Header Color Based on Screen Size

I am completely new to front-end development. I am in the process of building my own responsive website using Bootstrap 3. One issue I am facing is that when I resize my browser window to simulate a phone screen, I want the navigation bar color to change ...

What could be causing the canvas circle to appear distorted and not truly circular?

My simple code is intended to draw a circle, but it's not appearing as expected. The coordinates seem to be shifted oddly. The canvas size is specified with style="width: 600px; height: 600px;". I've tested it on both Chrome and Safari, yet the r ...

What makes a function in JavaScript special as both a constructor and an object?

After conducting extensive research on this topic, I have not been able to find a definitive answer. According to one source, when the JavaScript engine encounters a function statement, it creates a new Function() object, leading me to believe that it coul ...

Encountered an issue during my initial AJAX call

Hello everyone, I am currently attempting to use AJAX to send a request with a button trigger and display the response HTML file in a span area. However, I am encountering some issues and need help troubleshooting. Here is my code snippet: //ajax.php < ...

State dropdown in Angular dynamically updates based on the country selected

I am in search of a contextual state dropdown menu that is linked to the country, ensuring only relevant states are displayed. I have explored these two solutions for guidance in my project. Angularjs trigger country state dependency angularjs dependant ...

Execute an xmlhttprequest and then redirect to a different URL

I'm a beginner when it comes to AJAX and JavaScript. My goal is to first show a confirmation box, then send an XMLHttpRequest if confirmed. After that, I want to redirect the user to a new page. Below is my current code: <script type="text/javascr ...

Height of inline-block list items in ul is not properly adjusted

I am working on a horizontal navigation bar using inline-block for the li tags. Here is the code snippet: <ul> <li><a href="#">HOME</a></li> <li><a href="#">FEATURES</a></li> <li><a href ...

Tips for using regular expressions with the find method in JavaScript?

Welcome to my Object: let data = [{ "title": "User info", "category": "personal", "userId": "abc12345" }, { "title": "Customer Info", "category": ...

I must update a bootstrap class name within multiple layers of divs by referring to the parent class

My code structure is set up like this: <div id="main-parent"> <div class="child2"> <div> child2 </div> </div> <div>child3</div> - - - - <div class="ch ...