Steps to apply the nav-active class to a navigation using jQuery just once

Seeking assistance with a problem I am facing. I would like to add the nav-active class to an li element only once, meaning if a child element is selected, then the parent li should not have the nav-active class. Below is the code I am using, but it does not meet my requirements. Thank you in advance.

Here is the code snippet:

$('ul li').find('li').click(function(){
   var $this = $(this);
   $('li').removeClass('nav-active');
   $this.addClass('nav-active');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<nav id="menu" class="nav-main" role="navigation">
 <ul class="nav nav-main">
  <li class="nav-parent item-b">
   <a href="#">
    <i class="icon icon-global" aria-hidden="true"></i>
    <span>Global</span>
   </a>

   <ul class="nav nav-children">
    <li class="item-a">
     <a href="#">
      <span>News</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>Highlights</span>
     </a>
    </li>
   </ul>
  </li>
  <li class="nav-parent">
   <a href="#">
    <i class="icon icon-document-512"></i><span>My Documents</span>
   </a>
   <ul class="nav nav-children" id="menu1">
    <li>
     <a href="#">
      <span>My Download</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>My Wishlist</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>My New Documents</span></a>
     </li>
    </ul>
   </li>
   ...
   // Other list items and nested structures continue here
  </ul>
 </nav>

Answer №1

In your example, a console.log($(this) will display 2 elements in the console if you click on a child element. One for the child element and one for its parent li element. This behavior is known as event bubbling. To handle event bubbling properly, you need to stop propagating the event.

Here's how you can do it:

$('li').click(function(event){
  event.stopPropagation()
   var $this = $(this);
   $('li').removeClass('nav-active');
   $this.addClass('nav-active');
});
.nav-active a
{
  color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="menu" class="nav-main" role="navigation">
                                <ul class="nav nav-main">
                                    <li class="nav-parent item-b">
                                        <a href="#">
                                            <i class="icon icon-global" aria-hidden="true"></i>
                                            <span>Global</span>
                                        </a>

                                        <ul class="nav nav-children">
                                            <li class="item-a">
                                                <a href="#">
                                                     <span>News</span>
                                                </a>
                                            </li>
                                            <li>
                                                <a href="#">
                                                    <span>Highlights</span>
                                                </a>
                                            </li>
                                        </ul>
                                    </li>
                                    <li class="nav-parent">
                                        <a href="#">
...

                                    <li><hr class="separator" /></li>
                                    <li><a href="#"><i class="fa licon-calendar" aria-hidden="true" style="font-size:24px;"></i>Upcoming Events</a></li
                                ></ul>
                            </nav>

Answer №2

One way to ensure the click function is executed only once is to be mindful that clicking on a child element may also trigger a click event on its parent element. This can lead to $(this) unintentionally selecting the parent item whenever a child element is clicked.

I've added CSS for the .nav-active class to showcase how it works. Give it a shot!

$(document).ready(function(){
   $('nav li').one("click",function(){
     $('nav li').removeClass('nav-active');
     $(this).addClass('nav-active');
   })
})
.nav-active>a>span{
  font-size:20px;
  color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="menu" class="nav-main" role="navigation">
 <ul class="nav nav-main">
  <li class="nav-parent item-b">
   <a href="#">
    <i class="icon icon-global" aria-hidden="true"></i>
    <span>Global</span>
   </a>

   <ul class="nav nav-children">
    <li class="item-a">
     <a href="#">
      <span>News</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>Highlights</span>
     </a>
    </li>
   </ul>
  </li>
  <li class="nav-parent">
   <a href="#">
    <i class="icon icon-document-512"></i><span>My Documents</span>
   </a>
   <ul class="nav nav-children" id="menu1">
    <li>
     <a href="#">
      <span>My Download</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>My Wishlist</span>
     </a>
    </li>
    <li>
     <a href="#">
      <span>My New Documents</span></a>
     </li>
    </ul>
   </li>
   <li class="nav-parent"><!-- nav-expanded-->
    <a class="">
     <i class="icon icon-marketing-material" aria-hidden="true"></i>
     <span>Marketing Material</span>
    </a>
    <ul class="nav nav-children" id="menu1">
     <li>
      <a href="#">
       <span>Batch Download</span>
      </a>
     </li>
     <li>
      <a href="#">
       <span>Upload</span>
      </a>
     </li>
     <li>
      <a href="#">
       <span>Edit/Delete</span></a>
      </li>
      <li>
       <a href="#" onClick='document.getElementById("preview-frame").src="new-uploads.html";'>
        <span>New Uploads</span></a>
       </li>
       <li>
        <a href="#" onClick='document.getElementById("preview-frame").src="revision.html";'>
         <span>Revisions</span></a>
        </li>
        <li>
         <a href="#" onClick='document.getElementById("preview-frame").src="top-download.html";'>
          <span>Top Downloads</span></a>
         </li>
        </ul>
       </li>

       <li>
        <a href="#" onClick='document.getElementById("preview-frame").src="blank.html";'>
         <i class="icon icon-11111" aria-hidden="true"></i>
         <span>GML Forum</span>
        </a>
       </li>
       <li>
        <a href="#"  onClick='document.getElementById("preview-frame").src="index - Copy.html";'>
         <i class="icon icon-market-research" aria-hidden="true"></i>
         <span>Market Research</span>
        </a>
       </li>
       <li>
        <a href="#">
         <i class="icon icon-market-access-2" aria-hidden="true"></i>
         <span>Market Access</span>
        </a>
       </li>
       <li>
        <a href="#">
         <i class="icon icon-compete" aria-hidden="true"></i>
         <span>Competetive Intelligence</span>
        </a>
       </li>
       <li>
        <a href="#">
         <i class="icon icon-portal" aria-hidden="true"></i>
         <span>Portal Tutorial</span>
        </a>
       </li>
       <li>
        <a href="#">
         <i class="icon icon-new-product-launch" aria-hidden="true"></i>
         <span>New Product Launch</span>
        </a>
       </li>                                    
       <li class="nav-parent">
        <a href="#">
         <i class="icon icon-portal-admin"></i><span>Portal Administration</span>
        </a>
        <ul class="nav nav-children" id="menu1">
         <li>
          <a href="#" onClick='document.getElementById("preview-frame").src="abbot-social-media.html";'>
           <span>Social Media</span>
          </a>
         </li>
        </ul>
       </li>

       <li><hr class="separator" /></li>
       <li><a href="#"><i class="fa licon-calendar" aria-hidden="true" style="font-size:24px;"></i>Upcoming Events</a></li
        ></ul>
       </nav>

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

Combining properties of JavaScript objects into one

Just starting my Vue journey and encountering a slight challenge. Displayed below is a table with various items: Whenever an item is selected and its quantity increased, I need my addOptional method (optional) to update a variable with the item's qu ...

Angular, choose, establish a default option

Despite my attempts, I am struggling to set the default option for a select element using AngularJS. My Technologies: AngularJS, Angular-UI-router, Bootstrap Key HTML snippet: <select ng-model="selectedCompany" ng-options="c.name for c in companies" ...

"Enhancing Your List Design: Customizing CSS for Hover Effects on Images

I'm currently working on a CSS/HTML list that utilizes an image as the background and changes to a different image when hovered over. However, I've encountered an issue where the hover image is not aligning properly, leaving a noticeable gap. T ...

When an AJAX request is made, it can either return an array or a single object, potentially leading to

My proficiency in Javascript is definitely lacking, and I've only just begun to understand it. I have set up an AJAX call to an API using the GET method. The JSON data returned by the API is pretty standard. If I don't include an ID, I receive ...

Retrieve the information from the API and populate the tables with the data

I'm currently working on fetching API data and displaying it in tables, using mock data for now. Successfully implemented actions and reducers. Managed to call the API but encountered an issue with network calls where I see a blocked response content ...

Issue with CKEditor within a ColorBox dialog box

Could someone please assist me? I am facing an issue with my HTML page where I have incorporated a ColorBox modal popup. Inside the ColorBox popup, there is a CKEditor. The problem is as described below: In Internet Explorer, the CKEditor functions proper ...

The Typescript Decorator is triggered two times

I submitted a bug report regarding Typescript because I suspect there is an issue, although I'm seeking additional insights here as well. This is the scenario. When running the following code: class Person { @IsValueIn(['PETER', ' ...

transferring a document using axios, bypassing the FormData interface

One way to upload a file to the server is by using axios along with the FormData api. Here's an example: persist(photo){ let data = new FormData(); data.append('photo', photo); axios.post(`/api/photos/${this.user ...

Filtering a list in AngularJS based on a property of an object with a filter applied on it

I am facing an issue with filtering a list of objects based on their properties using the filter filter. The problem arises when certain object properties have filters applied to them that alter their displayed format (such as the formatDate filter in the ...

Parsing temporary storage of database query results

My experience with OOP languages like C# and Java has been good, but I am relatively new to JavaScript/TypeScript. I find callback functions confusing, especially when using them with the BaaS ParseDB. For example, finding all playlists for a certain user ...

Finding out which side of a cube has been clicked---Let's identify the side

Currently, I am in the process of developing a navigation menu and I am looking for a way to detect which side the user has clicked. Is it possible to achieve this using raycasting or is there an alternative method that would work better? If you require i ...

Creating a text box that displays an inverted input

Hello, I'm looking to create a text box where if I input 1 then 2, it will display 21. Then if I enter 3, it should show 321. I am currently using Vue.js on my front end. Here is what I have attempted so far: I experimented with methods such as watc ...

Retrieving various sets of JSON objects arrays

I have successfully stored an array of JSON objects in the database using the following code: function send_custom_markers() { var reponse = confirm("Send markers to selected contacts?"); if (reponse === true) { var json_markers = new ...

Managing state in React for a nested object while still maintaining the data type of the

Exploring the question further from this particular query Updating State in React for Nested Objects The process of updating nested state involves breaking down the object and reconstructing it as shown below: this.setState({ someProperty: { ...this.stat ...

using an external JavaScript function in the MongoDB shell

In my case, I have JavaScript functions that are stored in a JSON file: functions={} functions.a = function(){ return "returned" } I've come across tutorials suggesting that by importing this JSON file, I should be able to use these ...

What is the process by which a JavaScript Date object is converted to a string when you log it to the

Whenever I create objects in JavaScript and output them to the console, I typically see a JavaScript object displayed. For instance: var myObj = { bla: "foo" } console.log(myObj); This code will display: { bla: "foo" } However, whe ...

What is the process for embedding images and text within a nested division element?

I have a website layout with 4 main sections: header, left side, right side, and footer. I would like to further divide the header into two sections - left header and right header. The right header should contain an image along with other options like home ...

Rules for specifying title attribute for tag a in JavaScript

What is the best way to handle conditions for the a tag (links) when it has content in the title attribute? If there is no description available, how should the script be used? For instance: if ( $('a').attr('title') == 'on any ...

Is your URL getting cut off in jQuery?

How can I properly display a URL in an HTML table without it getting truncated? I'm attempting to show it within a table using jQuery, but it seems to be cutting off the URL. Here's a snippet of my code. Any suggestions on how to fix this? <! ...

Creating an inverted curve or border-radius for a div element is a design technique that can add

I've been tackling a project that requires me to style the border of a div in an inverted manner. To achieve this, I'm limited to using only CSS and JS without any plugins. I've searched through various online resources and similar questions ...