I have a wrapper container where I would like is so when I click on the name each piece of info shows just for that wrapper and when I click/close the ‘x’ button it only removes it for that button.
Using the forEach()
method it is showing and removing all of the inner containers except for just the ones that have been clicked.
I thought it might be possible doing with the this
keyword but I couldn’t get it to work.
I’m new to Javascript so any help would be hugely appreciated.
Codepen: https://codepen.io/anna_paul/pen/JjWPLjx
window.addEventListener('DOMContentLoaded', function() { let name = document.querySelectorAll('.name') let close = document.querySelectorAll('.close') let innerText = document.querySelectorAll('.inner-text') // ----- show text name.forEach(function(item){ item.addEventListener('click', function(){ innerText.forEach(function(inner){ inner.classList.add('active') }) }, false) }) // ---- hide text close.forEach(function(item){ item.addEventListener('click', function(){ innerText.forEach(function(inner){ inner.classList.remove('active') }) }, false) }) }) // DomContentLoaded
* {position: relative; box-sizing: border-box;} body { margin: 0; height: 100vh; width: 100%; display: flex; align-items: center; justify-content: center; } .wrapper { width: 10rem; background: #fafafa; padding: 1rem; margin: 1rem; } .inner-text { background: red; display:none; } .inner-text.active { display: block } .close { position: absolute; top: -5rem; right: 0rem; padding: .5rem; background: white; z-index: 2; } .name { background: yellow; padding: 1rem; cursor: pointer; }
<div class="wrapper"> <p class="name">Name</p> <div>Other content</div> <div class="inner-text"> <div class="close">x</div> <ul> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> </ul> </div> </div> <div class="wrapper"> <p class="name">Name</p> <div>Other content</div> <div class="inner-text"> <div class="close">x</div> <ul> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> </ul> </div> </div>
Advertisement
Answer
You’ve pretty much identified the issue in your question which is that you are looping over all the panels in your event handlers and adding/removing classes to all the panels. Instead, you can work with “event delegation” where you set up just one event handler at a common ancestor of all the panels and let the event “bubble” up to that ancestor and be handled there. Also, because the code for the show and the hide are so similar, you can just have one function for both.
Lastly, innerText
is not a great name for a variable as innerText
is actually a DOM element property name.
// If you place the script that holds this code just before the // closing BODY tag, you won't need to set up a DOMContentLoaded // event. document.querySelector(".masterWrapper").addEventListener("click", function(event){ // Check to see if the event originated at an element // we care about handling // Get a reference to the <div class="wrapper"> ancestor of the clicked element // and then find the <div class="inner-text"> descedant within it. const inner_text = event.target.closest(".wrapper").querySelector(".inner-text"); // When Name is clicked if(event.target.classList.contains("name")){ // If the panel is not already showing its content: if(!inner_text.classList.contains("active")){ inner_text.classList.add("active"); } } // When the X is clicked if(event.target.classList.contains("close")){ event.target.parentElement.classList.remove("active"); } });
* {position: relative; box-sizing: border-box;} body { margin: 0; height: 100vh; width: 100%; display: flex; align-items: center; justify-content: center; } .wrapper { width: 10rem; background: #fafafa; padding: 1rem; margin: 1rem; } .inner-text { background: red; display:none; } .inner-text.active { display: block } .close { position: absolute; top: -5rem; right: 0rem; padding: .5rem; background: white; z-index: 2; } .name { background: yellow; padding: 1rem; cursor: pointer; }
<div class="masterWrapper"> <div class="wrapper"> <p class="name">Name</p> <div>Other content</div> <div class="inner-text"> <div class="close">x</div> <ul> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> </ul> </div> </div> <div class="wrapper"> <p class="name">Name</p> <div>Other content</div> <div class="inner-text"> <div class="close">x</div> <ul> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> <li>INFO</li> </ul> </div> </div> </div>