Is there a way to trigger a dropdown menu when my 'li' element is clicked on the Services option?

I need help creating a customized navigation bar. I want the Services and Plans list items to display drop-down menus when clicked. However, instead of working as expected, I'm encountering an error message that says: 'cannot read property contains of undefined'. My goal is to select the sub-menu class and add the sub-menu-active class (which is set in my CSS to display as block). Initially, I have set the display property in my CSS file to 'none'.

Here is the HTML file I am working with:

<nav class="custom-navigationbar-container" >
    <ul class="menu">
        <li class="logo"><a href="#">Home</a></li>
        <li class="item"><a href="#">About</a></li>
        <li class="item"><a href="#">Blog</a></li>
        <li class="item special">
            <a tabindex="0">Services <i class="fas fa-sort-down"></i></a>
            <ul class="sub-menu" >
                <li class="sub-item" ><a href="#">Web Design</a></li>
                <li class="sub-item" ><a href="#">Web Development</a></li>
                <li class="sub-item" ><a href="#">SEO</a></li>
                <li class="sub-item" ><a href="#">Digital Marketing</a></li>
            </ul>
        </li>
        <li class="item special has-sub-menu">
            <a tabindex="0">Plans <i class="fas fa-sort-down"></i></a>
            <ul class="sub-menu">
                <li class="sub-item" ><a href="#">Freelancer</a></li>
                <li class="sub-item" ><a href="#">StartUp</a></li>
                <li class="sub-item" ><a href="#">Enterprise</a></li>
            </ul>
        </li>
        <li class="item" ><a href="#">Blog</a></li>
        <li class="item" ><a href="#">Contact</a></li>
        <li class="item button" ><a href="#">Log In</a></li>
        <li class="item button secondary" ><a href="#">Sign Up</a></li>
        <li class="toggle"><a href="#"><i class="fas fa-bars" ></i></a></li>
    </ul>
</nav>

This is the .Js code

const special = document.querySelectorAll(".special");
const specialToggle = function(){
    const subMenu = this.getElementsByClassName('sub-menu');
    if(subMenu.classList.contains(".sub-menu-active")){
        console.log('I am removing sub-menu-active now');
        ul.classList.remove('.sub-menu-active');
    }else{
        console.log('I am adding sub-menu-active now');
        ul.classList.add('.sub-menu-active'); 
    }
    
};

for(const specials of special){
    specials.addEventListener('click', specialToggle)
}

Answer №1

Your primary issue lies within this line of code:

const subMenu = this.getElementsByClassName('sub-menu');

Instead of returning a single element, this will actually return a collection of elements or no elements at all.

To address this, you might want to try the following approach:

const subMenu = this.getElementsByClassName('sub-menu')[0];

However, keep in mind that this method will only target the first element even if there are multiple ones.

A more effective solution would be to capture the event within the function, identify the parent of the target element, and then locate the 'sub-menu' within it. This way, you ensure accuracy:

const subMenu = e.target.parentElement.getElementsByClassName('sub-menu')

For demonstration purposes, here's an enhanced version of your code applied to a simplified HTML structure:

const special = document.querySelectorAll(".special");
const specialToggle = function(e){
    const subMenu = e.target.parentElement.getElementsByClassName('sub-menu')[0];
    if (subMenu == null) {
        console.log('No sub-menu found. It is possible that you clicked on a child element.');
    } else if(subMenu.classList.contains(".sub-menu-active")){
        console.log('Removing "sub-menu-active" class now');
        subMenu.classList.remove('.sub-menu-active');
    } else{
        console.log('Adding "sub-menu-active" class now');
        subMenu.classList.add('.sub-menu-active'); 
    }
    
};

for(const specials of special){
    specials.addEventListener('click', specialToggle)
}
<ul class="menu">
    <li class="logo"><a href="#">Home</a></li>
    <li class="item special">
        <a tabindex="0">Services <i class="fas fa-sort-down"></i></a>
        <ul class="sub-menu" >
            <li class="sub-item" ><a href="#">Web Design</a></li>
            <li class="sub-item" ><a href="#">Web Development</a></li>
        </ul>
    </li>
    <li class="item special has-sub-menu">
        <a tabindex="0">Plans <i class="fas fa-sort-down"></i></a>
        <ul class="sub-menu">
            <li class="sub-item" ><a href="#">Freelancer</a></li>
            <li class="sub-item" ><a href="#">StartUp</a></li>
        </ul>
    </li>
</ul>

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

Angular protects routes by using tokens stored in cookies

I typically store the user token in local storage and use the "token" key in local storage as a method to protect certain routes in my application. If the key is present, I allow the user to access the page, but if it's not, I redirect them to the log ...

Exploring the differences between a fixed-top navbar and dark theme in Bootstrap 5.3

I've been struggling to find a solution for having a fixed top navigation bar that remains solid without being transparent in both dark and light themes. Switching between dark and light themes results in the fixed-top navigation bar appearing transp ...

Transitioning from the traditional LeftNav menu style to the more versatile composability feature using Reactjs with Material-ui

Hey there, I'm facing a bit of confusion while trying to create a LeftNav menu using material-ui. I recently joined this project and updated reactjs and material-ui. Unfortunately, many things related to LeftNav in material-ui have been deprecated, ...

Responsive Slider

In the current project I'm working on, I'm creating a team page that features a slider element. Originally, my goal was to replicate the functionality of the slick library without importing slick, jQuery, and also improve my JavaScript skills. ...

merging the central pair of columns in the bottom row

I am having trouble combining the middle two columns in the third row of my table code. The columns remain separate and do not merge as intended. Can anyone help me identify what is causing this issue in my code? table { border: 1px solid #999; } td ...

Streamlining a map-generated object

Looking to streamline this code, specifically the declaration of the variable codes. Is there a way to simplify this? const numbers = [ { id1: 1, id2: 2, id3: 3, pos: "a" }, { id1: 4, id2: 5, id3: 6, pos: "b" }, { id1: 7, id2: 8, ...

Passing a Typescript object as a parameter in a function call

modifications: { babelSetup?: TransformationModifier<babel.Configuration>, } = {} While examining some code in a React project, I came across the above snippet that is passed as an argument to a function. As far as I can tell, the modifications p ...

How can I extract the value of a JavaScript variable using jsoup in an HTML document?

<html> <script type="text/javascript"> var map = null; jQuery(function($) { L.marker([50.065407, 19.945104], {title: 'Cat'}) .bindPopup('<h3>Cat</h3> ...

Help with Web Scraping: Setting up Noodle.js and Using jQuery

After successfully installing noodle.js using npm install, my code looks like this. However, when I try to run the file (noodleTest.js) in the terminal with the command 'node noodleTest.js', I encounter the error message: jQuery.getJSON is not a ...

Functionality of multiple sliders

Is there a more efficient way to handle the fading in and out of sections on a slider? I currently have separate functions for each section, but I'd like to simplify it so that I only need one function for all 100 sections. Any suggestions? $(&apos ...

Utilize an Ajax dropdown menu that allows users to enter search criteria, such as location or city

Looking for a way to display weather information based on a selected city? Check out this code snippet that uses Yahoo API to pull data and show weather details. Here's the code: <HTML> <HEAD> <TITLE>Find Weather in major cities ar ...

After running JavaScript, retrieve the canvas data using the toDataUrl() method

After working on a Javascript function that creates a canvas and writes an image and text on it, I was expecting to get the base64 dataUrl. However, all I end up with is a blank canvas. Check out the code snippet below: function createBreadCrumb(label) ...

The issue of TypeError arising while invoking a method within TypeScript Class Inheritance

Currently, I am developing a Node.js application with TypeScript. In this project, I have a base controller class named BaseController and a derived controller called SettingController. The intention is for the SettingController to utilize methods from the ...

Three.js performance degrades when dealing with a large number of objects

Currently, I am facing performance issues while creating over 12,000 BoxHelpers. The loading and navigating processes are extremely slow. I am seeking advice on a more efficient approach. This is the code snippet that I am using: var c=[]; c.push([- ...

Struggling to deploy my Laravel application with Tailwind CSS on the frontend. However, running "npm run dev" results in an error

While running the npm command `npm run dev` in cmd, I encountered an error stating that I require PostCSS v8 even though I already have PostCSS v8.3 installed. Could it be possible that Tailwind CSS specifically needs version 8 despite newer versions being ...

What is the reason that methods such as 'filter' and 'map' are ineffective in the 'ngFor' directive of Angular?

As I was experimenting with Angular templates, I discovered that certain array functions like slice() work smoothly with the ngFor directive expression, as shown below: <div *ngFor="let item of arry.slice(3)"> {{ item.name }} </div> However ...

Removing items from a todo list in JSX without relying on props or state

I am facing a challenge with utilizing a function to delete an item from an array when clicking the delete button. I am seeking a solution without relying on props or state. Could someone please point out where I may be making a mistake? The item appears ...

Is there a more efficient method for showcasing model objects in Thymeleaf rather than utilizing a form?

I've been exploring Spring Boot, Thymeleaf, and frontend development in general. Currently, I have a frontend table that displays a list of objects from the backend, along with a form to allow users to view properties of each item in the list. Howeve ...

State remains stagnant following update from use state

Recently diving into React, I've been experimenting with getting my socket io listener up and running smoothly. Interestingly, when I have it placed outside of the useEffect, it seems to function but gets called multiple times. However, when nestled w ...

Utilizing the p tag to incorporate dynamic data in a single line

I am currently working with two JSON files named contacts and workers. Using the workerId present in the contacts JSON, I have implemented a loop to display workers associated with each contact. The current display looks like this: https://i.sstatic.net/AR ...