How can I target each item in a list with collapsible items?

Viewed 136

I have a list of div elements, each containing a header and a body section. Only the header of each item is initially displayed, and when clicked, the corresponding body should appear below the header. When the header is clicked again, the body should disappear. The logic I use is to append/remove the class name "extended" on each list item, in order to display and hide the body section through CSS.

Now, I am trying to create a dynamic script to allow virtually infinite list entries, without having to target each item specifically, but I cannot get it to work for all items.

HTML

<div class="list-wrapper">
    <div class="chapter chapter-1">
        <div class="chapter-header"></div>
        <div class="chapter-body"></div>
    </div>
    <div class="chapter chapter-2">
        <div class="chapter-header"></div>
        <div class="chapter-body"></div>
    </div>
    <div class="chapter chapter-3">
        <div class="chapter-header"></div>
        <div class="chapter-body"></div>
    </div>
</div>

JavaScript

var chapter = document.getElementsByClassName('chapter')[0];
var chapterHeader = document.getElementsByClassName('chapter-header')[0];

chapterHeader.addEventListener("click", function(){
    chapter.classList.toggle("extended");
});

The code above works fine for the first item but obviously not for the rest. Any ideas ? I'm interested in vanilla JavaScript code. Thanks in advance.

3 Answers

You need to use method forEach() to work with a collection of classes. And also method closest(), which allows you to refer to the specified parent of the current element.

Try this it code:

let chapterHeader = document.querySelectorAll('.chapter-header');

chapterHeader.forEach(function(chapterHeader_current, index) {
  chapterHeader_current.addEventListener('click', function() {
    let current_chapter = this.closest('.chapter');
    current_chapter.classList.toggle("extended");
  });
});

Event bubbling is the keyword.

Add only one event to the container. When you click on the container it first handles the inner element and then the outer elements.

let list = document.getElementById("myList");

list.addEventListener("click", function(event) {
  // Do stuff with target
  console.log(event.target.className);

})
<div id="myList" class="list-wrapper">
  <div class="chapter chapter-1">
    <div class="chapter-header">Chapter header 1</div>
    <div class="chapter-body">Chapter body 1</div>
  </div>
  <div class="chapter chapter-2">
    <div class="chapter-header">Chapter header 2</div>
    <div class="chapter-body">Chapter body 2</div>
  </div>
  <div class="chapter chapter-3">
    <div class="chapter-header">Chapter header 3</div>
    <div class="chapter-body">Chapter body 2</div>
  </div>
</div>

something like this i believe

chapterHeader.addEventListener("click", function(this){
        this.nextSibling.classList.toggle("extended");
    });
Related