I wrote toggle script in ES6/vanilla JS. The intended functionality is super simple, you click on the toggle div and it adds an active
class to another div that matches the toggle div's data-toggle
property. In my toggle div, I need there to be both text and an image. It works great when you click on the text within the div, but when you click on the image within the div, the toggle is not firing. Is there something specific I need to do to include all of the children within the div?
For some reason, I can't even get this working via this code snippet editor, but it is working in my project.
const setActive = (toggles, panels, id) => { let activePanel = panels.filter(panel => panel.getAttribute('data-toggle') == id) let activeToggle = toggles.filter(toggle => toggle.getAttribute('data-toggle') == id) activePanel.forEach(panel => panel.classList.add('active')) activeToggle.forEach(toggle => toggle.classList.add('active')) } const removeActive = (nodes) => { nodes.forEach(node => node.classList.remove('active')) } const handler = (event) => { event.preventDefault() let id = event.target.getAttribute('data-toggle') let panels = Array(...document.querySelectorAll('.js-toggle-panel')) let toggles = Array(...document.querySelectorAll('.js-toggle')) removeActive(panels) removeActive(toggles) setActive(toggles, panels, id) } let toggles = Array(...document.querySelectorAll('.js-toggle')) toggles.forEach(toggle => toggle.addEventListener('click', handler))
.toggle-panel { display: none; } .toggle-panel .active { display: block; }
<div class="js-toggle toggle" data-toggle="toggle-1"> <img src="https://via.placeholder.com/50"> First toggle </div> <div class="js-toggle toggle" data-toggle="toggle-2"> Second toggle </div> <div class="js-toggle-panel toggle-panel" data-toggle="toggle-1"> <h1>Toggle 1</h1> </div> <div class="js-toggle-panel toggle-panel" data-toggle="toggle-2"> <h1>Second toggle!</h1> </div>
Instead of event.target
you should use event.currentTarget
in your handler
function to return node to which event listener is attached. event.target
is returning <img>
node, not <div>
with data-toggle
in your case.
I changed two things that I believe will resolve your issue:
.toggle-panel .active
to .toggle-panel.active
-- without that, even in the cases where the JS was working as you intended nothing was actually be made visible. event.target
to event.currentTarget
-- the former always points to the clicked element, whereas the latter refers to the element on which the listener has been placed. See the snippet below.
const setActive = (toggles, panels, id) => { let activePanel = panels.filter(panel => panel.getAttribute('data-toggle') == id) let activeToggle = toggles.filter(toggle => toggle.getAttribute('data-toggle') == id) activePanel.forEach(panel => panel.classList.add('active')) activeToggle.forEach(toggle => toggle.classList.add('active')) } const removeActive = (nodes) => { nodes.forEach(node => node.classList.remove('active')) } const handler = (event) => { event.preventDefault() let id = event.currentTarget.getAttribute('data-toggle') let panels = Array(...document.querySelectorAll('.js-toggle-panel')) let toggles = Array(...document.querySelectorAll('.js-toggle')) removeActive(panels) removeActive(toggles) setActive(toggles, panels, id) } let toggles = Array(...document.querySelectorAll('.js-toggle')) toggles.forEach(toggle => toggle.addEventListener('click', handler))
.toggle-panel { display: none; } .toggle-panel.active { display: block; }
<div class="js-toggle toggle" data-toggle="toggle-1"> <img src="https://via.placeholder.com/50"> First toggle </div> <div class="js-toggle toggle" data-toggle="toggle-2"> Second toggle </div> <div class="js-toggle-panel toggle-panel" data-toggle="toggle-1"> <h1>Toggle 1</h1> </div> <div class="js-toggle-panel toggle-panel" data-toggle="toggle-2"> <h1>Second toggle!</h1> </div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.