The act of selecting a parent element appears to trigger the selection of its child elements as well

I am attempting to create an accordion using Vanilla JavaScript, but I have encountered an issue. When there is a child div element inside the header of the accordion, it does not seem to work and I'm unsure why. However, if there is no child div element, the accordion functions properly.

    var coll = document.getElementsByClassName("m40__grid__item");
coll[i].addEventListener("click", function (evnt) {
    let target = evnt.target;
    if ( !target.matches('.m40__grid__item') ) {
        target = target.closest('.m40__grid__item');
    }
    const currClassList = target.classList;
    if (currClassList.contains("active")) {
      evnt.target.classList.remove("active");
      var content = evnt.target.nextElementSibling;
      content.style.maxHeight = null;
    } else {
      for (var j = 0; j < coll.length; j++) {
        coll[j].classList.remove("active");
        coll[j].nextElementSibling.style.maxHeight = null;
      }
      this.classList.toggle("active");
      var content = this.nextElementSibling;
      if (content.style.maxHeight) {
        content.style.maxHeight = null;
      } else {
        content.style.maxHeight = content.scrollHeight + "px";
      }
    }
  });
}
<div class="m40__grid">
  <div class="m40__grid__item">
    <div class="test">
      This header doesn't work
    </div>
  </div>
  <div class="m40__grid__item--full-width">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>

  <div class="m40__grid__item">Click me!</div>
  <div class="m40__grid__item--full-width">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

The code pen showcasing my issue can be found here: https://codepen.io/mrsalami/pen/WNrBboR?editors=1111

Answer №1

It is my understanding that event.target could potentially be div.test, therefore it is necessary to standardize the target as shown below:

var newTarget = event.target;
if (!newTarget.matches('.m40__grid__item')) {
 newTarget = newTarget.closest('.m40__grid__item');
}

Once this process is complete, you should proceed with using newTarget.

Answer №2

After some tweaking, I believe this solution will be effective. The key change made was removing the line "coll[j].nextElementSibling.style.maxHeight = null;" from within the loop.

var coll = document.getElementsByClassName("m40__grid__item");
for (var i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function (evnt) {
    const currClassList = evnt.target.classList;
    if (currClassList.contains("active")) {
      evnt.target.classList.remove("active");
      var content = evnt.target.nextElementSibling;
      content.style.maxHeight = null;
    } else {
      for (var j = 0; j < coll.length; j++) {
        coll[j].classList.remove("active");
      }
      this.classList.toggle("active");
      var content = this.nextElementSibling;
      if (content.style.maxHeight) {
        content.style.maxHeight = null;
      } else {
        content.style.maxHeight = content.scrollHeight + "px";
      }
    }
  });
}

Answer №3

Choice 1

If you're looking for a quick solution, simply apply this CSS:

.test {
    pointer-events: none;
}

This will render the element unresponsive to mouse clicks.

Choice 2

If you prefer a more effective fix, here's where you might be going wrong: evnt.target provides the actual target of the click event, which is the innermost element being hovered by the mouse when clicked. Hence, this approach may not always accurately identify the element to which you should add/remove the class active.

@AngelSalazar has proposed an excellent workaround for this issue, so I'll go ahead and share his solution:

coll[i].addEventListener("click", function (evnt) {
    let target = evnt.target;
    if (!target.matches('.m40__grid__item')) {
        target = target.closest('.m40__grid__item');
    }
    const currClassList = target.classList;
    ...

This method traverses through the element's parents in reverse order to find a match for the selector, ensuring that you interact with the header rather than one of its children.

Here's the functioning solution, inspired by the provided codepen example.

var coll = document.getElementsByClassName("m40__grid__item");
for (var i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function (evnt) {
    
    let target = evnt.target;
    if (!target.matches('.m40__grid__item')) {
        target = target.closest('.m40__grid__item');
    }
    const currClassList = target.classList;
    if (currClassList.contains("active")) {
      target.classList.remove("active");
      var content = target.nextElementSibling;
      content.style.maxHeight = null;
    } else {
      for (var j = 0; j < coll.length; j++) {
        coll[j].classList.remove("active");
        coll[j].nextElementSibling.style.maxHeight = null;
      }
      this.classList.toggle("active");
      var content = this.nextElementSibling;
      if (content.style.maxHeight) {
        content.style.maxHeight = null;
      } else {
        content.style.maxHeight = content.scrollHeight + "px";
      }
    }
  });
}
.m40__grid__item {
  background-color: #777;
  color: white;
  cursor: pointer;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.active, .m40__grid__item:hover {
  background-color: #555;
}

.m40__grid__item:after {
    font-family: 'FontAwesome'; /* essential to enable caret symbol*/
    content: "\f067";
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
      margin-right: 30px;
}

.active:after {
 content: "\f068";
}

.m40__grid__item--full-width {
  padding: 0 18px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  background-color: #f1f1f1;
}
<div class="m40__grid">
<div class="m40__grid__item">
  <div class="test">
    This header doesn't work
  </div>
</div>
<div class="m40__grid__item--full-width">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

<div class="m40__grid__item">Click me!</div>
<div class="m40__grid__item--full-width">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>



</div>

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

Is nesting possible with the &:extend function in LessCss?

I've recently been exploring the Less &:extend feature. My goal is to nest multiple extends - essentially extending a class that itself extends another class. However, after testing it out, I'm not sure if it's working as expected. It ...

Best practices for handling multiple tables in AngularJS HTML

How can I loop through multiple tables in AngularJS? Here is an example of my HTML code: <div ng-repeat="stuff in moreStuff"> <table> <h1>{{stuff.name}}</h1> <tr ng-repeat="car in cars"> <td> ...

Vertical and floating alignment

Can you help me with this HTML/CSS challenge? User: Support: Emily Johnson Alex Roberts I am looking to have two input boxes aligned vertically on both the left and right ...

Unable to locate the CSS file

I'm struggling to link a stylesheet file to my 'base.html' template that is used throughout my entire project. Here's the path to the file I want to link: C:\forum_project\static\main\css\style.css Below is ...

Dealing with transformed data in AngularJS: Best practices

Scenario I have a dataset structured like: [{ xRatio: 0.2, yRatio: 0.1, value: 15 }, { xRatio: 0.6, yRatio: -0.3, value: 8 }] I need to convert this data into absolute values for display in a ng-repeat. However, when I attempt to do so usin ...

A guide to successfully interacting with multiple elements simultaneously at a single spot

Within my graphic chart, I have various dots that may be located in the same spot. I am looking for a way to handle clicks on two or more elements simultaneously in Vue 3. Do you know of any straightforward methods to achieve this? I attempted using refs ...

Utilizing the Pub/Sub architecture to integrate the kafka-node library within Node Js

Utilizing the kafka-node module in my NodeJs Microservise project, I am aiming to implement a Pub/Sub (publisher and subscriber) design pattern within the Functional programming paradigm. producer.js const client = new kafka.KafkaClient({ kafkaHost: ...

Looking for a way to extract a dynamic URL from a website's div element?

Is there a way for my app to load dynamically by extracting and reading the changing URL from a webpage? //webpage <div style="display:none" id="urladdress"> //dynamic url **https://freeuk30.listen2myradio.co ...

Having trouble with redundant code while updating state in ReactJS - React JS

Currently, I am working on a prayer times web app using reactJS (nextjs). To achieve this, I first fetch the geolocation coordinates and then retrieve the city and country name based on these coordinates. Following that, I obtain the prayer times for the s ...

Fixing perspective clipping in Three.js

In my Three.js project, I have a plane inside a sphere that I am applying a shader to in order to achieve certain visual effects on the sphere. To ensure that the plane is always facing the camera, I am using the lookAt method. However, I have noticed that ...

What is the method to obtain an object as the return value from a click function in JavaScript?

I would like to retrieve the cell value from a table by clicking on a button. I have already created a function called getDetail in JavaScript that is implemented on the button, but I am facing difficulty in returning the value from the function. <butto ...

How about having a surprise image pop up when you click a button?

I've been working on coding a button that can change the background of my webpage to display a random image. Initially, my code seemed functional, but it was only displaying the last image listed in my series of if/else statements. I suspect that usin ...

Guide on showing string array values in an alert popup using JavaScript

I am struggling to display a string array in a JavaScript alert popup. The goal is to show the string index or Serial Number, followed by a space and then a line break before displaying the value of each string in the array. Unfortunately, my current code ...

Fade in text effect using jQuery on a Mac computer

Trying to create a smooth text fading effect across different browsers using jQuery. In the example below, you may notice that during the last part of the animation when the text fades in, the font weight suddenly increases causing a jerky/clunky appearan ...

Compiling with GatsbyJs throws an abrupt token error with 'if' being an unexpected token

I am working on a code snippet in GatsbyJS where I am extracting data from a StaticQuery using GraphQL and then rendering a component. The challenge I am facing is to conditionally check if a specific sub-object exists within the data object, and if it doe ...

Identify a specific HTML template using jQuery

I am currently working on implementing datepickers in various HTML templates. The issue I am facing is that the functionality only seems to work in my index.html file. When I try to replicate the same setup in another template, it does not function proper ...

Creating a functionality in jQuery that allows users to dynamically add a new row by clicking a button

Hello all, I am currently facing an issue with my code where I need to call a text box (or a set of divs with input fields) multiple times by clicking a button (with the id 'add_row'). The current code works fine for the first time, but not for ...

Is there a reason we are able to simultaneously assign the disabled and selected attributes to <option> elements?

What is the rationale behind permitting the simultaneous setting of disabled and selected attributes on <option> elements, knowing that their values will not be submitted to a server? I was surprised that I did not receive an error in VS Code when I ...

What is the reason for Nightwatch running each .js file as a Child process? Could it be due to alterations in the configuration settings

Recently, I've been experiencing an issue when running Nightwatch.js where my console is spawning child processes for every .js file in each folder and subfolder. Multiple Chrome instances are opening along with them and even the module folders with r ...

The search results fail to show the required information

I am trying to retrieve data from an API based on a search query. When the user enters the name of the film they are looking for and hits enter to submit the form, the matching films should be displayed on the screen. However, my console is showing errors ...