I have a menu list where icons are placed next to the menu label. One menu item has a sub-menu that is expanded with JavaScript. If I click anywhere within the menu item, the sub-menu expands. However, if I click on the icon embedded in the menu item or the label, the sub-menu won't expand. All other menu items that don't use JavaScript to expand sub-menus fire correctly when clicking on the icon or other parts of the menu item.
// Show an element
var show = function (elem) {
// Get the natural height of the element
var getHeight = function () {
elem.style.display = 'block'; // Make it visible
var height = elem.scrollHeight + 'px'; // Get it's height
elem.style.display = ''; // Hide it again
return height;
};
var height = getHeight(); // Get the natural height
elem.classList.add('is-visible'); // Make the element visible
elem.style.height = height; // Update the max-height
// Once the transition is complete, remove the inline max-height so the content can scale responsively
window.setTimeout(function () {
elem.style.height = '';
}, 350);
};
// Hide an element
var hide = function (elem) {
// Give the element a height to change from
elem.style.height = elem.scrollHeight + 'px';
// Set the height back to 0
window.setTimeout(function () {
elem.style.height = '0';
}, 1);
// When the transition is complete, hide it
window.setTimeout(function () {
elem.classList.remove('is-visible');
}, 300);
};
// Toggle element visibility
var toggle = function (elem, timing) {
// If the element is visible, hide it
if (elem.classList.contains('is-visible')) {
hide(elem);
return;
}
// Otherwise, show it
show(elem);
};
// Listen for click events
document.addEventListener('click', function (event) {
// Make sure clicked element is our toggle
if (!event.target.classList.contains('toggle')) return;
// Prevent default link behavior
event.preventDefault();
// Get the content
var content = document.querySelector(event.target.hash);
if (!content) return;
// Toggle the content
toggle(content);
}, false);
ul {
font-family: sans-serif;
list-style-type: none;
width: 230px;
}
li {
color: #404040;
font-size: 0.75rem;
letter-spacing: -0.4px;
line-height: 1.025rem;
text-transform: uppercase;
}
li ul {
padding: 0;
margin: 0;
}
li img {
margin-right: 1rem;
}
li a {
color: inherit;
display: block;
padding: 0.875rem 1.5rem 1.025rem;
text-decoration: none;
}
li a:hover {
background-color: #f2f6f9;
}
li span {
position: relative;
top: -.25rem;
}
li li {
background-color: transparent;
}
.toggle {
border-left: 5px solid #015295;
padding-left: calc(1.5rem - 5px);
}
.toggle-content {
display: none;
height: 0;
overflow: hidden;
transition: height .3s ease-in-out;
}
.toggle-content.is-visible {
display: block;
height: auto;
}
<ul>
<li><a href="http://isitchristmas.com">
<img src="https://image.flaticon.com/icons/svg/263/263115.svg" width="20" height="20" alt=""><span>Home</span></a></li>
<li style="background-color: #f2f6f9;"><a class="toggle" href="#example"><img src="https://image.flaticon.com/icons/svg/263/263078.svg" width="20" height="20" alt=""><span>Billing</span>
</a>
<div class="toggle-content" id="example">
<ul>
<li><a href="http://isitchristmas.com">Premium Statement</a></li>
<li><a href="http://isitchristmas.com">Payment Summary</a></li>
</ul>
</div>
</li>
<li><a href="http://isitchristmas.com">
<img src="https://image.flaticon.com/icons/svg/263/263058.svg" width="20" height="20" alt=""><span>Employees</span></a></li>
<li><a href="http://isitchristmas.com"><img src="https://image.flaticon.com/icons/svg/263/263146.svg" width="20" height="20" alt=""><span>Claims</span></a></li>
<li><a href="http://isitchristmas.com"><img src="https://image.flaticon.com/icons/svg/263/263122.svg" width="20" height="20" alt=""><span>My Plans</span></a></li>
</ul>
I don't know why clicking on the icon embedded in the link would prevent the JavaScript from firing. Any help is appreciated.
It's because the "event.target" returns the exact DOM element, so in your code, when you click on the "img" or on the "span", the "event.target" will return
<img src="https://image.flaticon.com/icons/svg/263/263078.svg" width="20" height="20" alt="">
or
<span>Billing</span>
In order to prevent this you should use : .closest('a')
it will go to the closest element that fit the description.
// Make sure clicked element is our toggle
if (!event.target.closest('a').classList.contains('toggle')) {
return;
}
// Prevent default link behavior
event.preventDefault();
// Get the content
console.log(event.target.closest('a').hash);
var content = document.querySelector(event.target.closest('a').hash);
if (!content) return;
This is my small modification to your code, it should work now.
To understand more about .closest()
read here : https://developer.mozilla.org/en-US/docs/Web/API/Element/closest