This is the markup that I'm working with
<div class="checkout-row__form-column__billing">
<div class="checkout-row__form-column__billing__title billing-collapse collapse-btn">
<div class="checkout-row__form-column__billing__title__arrow">
<i class="fa fa-chevron-right" aria-hidden="true"></i>
</div>
<h2>1. Billing Details</h2>
</div>
<div class="checkout-row__form-column__shipping__content shipping-collapse-content collapse-target"></div>
<div class="checkout-row__form-column__shipping">
<div class="checkout-row__form-column__shipping__title shipping-collapse collapse-btn">
<div class="checkout-row__form-column__shipping__title__arrow">
<i class="fa fa-chevron-right" aria-hidden="true"></i>
</div>
<h2>2. Shipping Details</h2>
</div>
<div class="checkout-row__form-column__shipping__content shipping-collapse-content collapse-target"></div>
All this markup is wrapped in div with a class of checkout-row__form-column.
So, I'm grabbing the parent wrapper, on click I match target with .collapse-btn. and then I do class toggle on the sibling which is .collapse-target. Works great except on issue, that I can't get past. If I click on the inner element, the event doesn't happen.
Here is my js
parent = document.querySelector('.checkout-row__form-column');
parent.addEventListener('click', (e)=>{
if (e.target.matches('.collapse-btn')) {
e.stopPropagation();
e.target.nextElementSibling.classList.toggle('hide');
}
});
With these code I am able to toggle classes if I don't click on i element or h2. How can I write my JavaScript that event will be fired if I click anywhere inside the e.target.
Any help is much appreciated fellow commarades.
Your code only checks if the
event.targetis the.collapse-btnelement or not. You also need to check if the clicked element is a descendant element of the.collapse-btnelement.To achieve the desired result, you can use the two conditions to check if the
event.targetis the.collapse-btnor any of its descendant. To check for descendant elements, use the universal selector*.Demo
Following snippet shows an example:
You could also put the selectors in an array and then use
.some()method to check ifevent.targetmatches ay of the selector in the array.Demo
Following snippet shows an example:
Alternative Solution
Instead of using the
.matches()method, use the combination ofElement.closest()andNode.contains()methods to check if theevent.targetis the.collapse-btnelement or is a child element of the.collapse-btnelement.For this to work, you need to do two steps:
You first need to get the
.collapse-btnthat is the closest ancestor of theevent.target.After that, you need to check if the
event.targetis a descendant of the button selected in step 1.Code:
If
event.targetis the.collapse-btnitself, thenwill return the
e.target, i.e..collapse-btnandwill also return true because
.contains()method returns true even if the node passed to it as an argument is the same node as the one on which.contains()method was called.So using
.closest()and.contains()methods in this way covers both the use cases, i.e. when.collapse-btnis clicked or when any of its descendant element is clicked.Demo
Following snippet shows a simple example: