dropdown menu is created in shadowDOM
almost perfect, but the problem is how to hide the dropdown menu when click on any where else in window
class NavC
An unrelated suggestion: you should probably separate .dropdown
into its own
component and assign the 'click' event listeners in its 'constructor' or 'connectedCallback'.
The best idea for your problem is to
ddc[index].addEventListener('click', e => {
if(dd[index].classList.contains('show')) {
dd[index].classList.remove('show');
window.removeEventListener('click', handleDropdownUnfocus, true);
}
else {
dd[index].classList.add('show');
window.addEventListener('click', handleDropdownUnfocus, true);
}
});
Note: I use addEventListener with true
, such that the event happens at capture, so that it's will not happen immediately after the .dropdown click handler.
And your handleDropdownUnfocus
will look like
function handleDropdownUnfocus(e) {
Array.from(document.querySelectorAll('app-nav')).forEach(function(appNav) {
Array.from(appNav.shadowRoot.querySelectorAll('.dropdown')).forEach(function(dd) {
dd.classList.remove('show');
});
});
window.removeEventListener('click', handleDropdownUnfocus, true);
}
There's a problem with this solution though, that if you click on the menu item again after opening it, it will call both .dropdown
and window
handlers, and the net result will be that the dropdown will remain open. To fix that, you would normally add a check in handleDropdownUnfocus
:
if(e.target.closest('.dropdown')) return;
However, it will not work. Even when you click on .dropdown
, your e.target
will be app-nav
element, due to Shadow DOM. Which makes it more difficult to do the toggling. I don't know how you'd address this issue, maybe you can come up with something fancy, or stop using Shadow DOM.
Also, your code has some red flags... For example, you use let
keyword in your for-loop, which is fine. The support for let
is very limited still, so you're more likely going to transpile. The transpiler will just change every let
to var
. However, if you use var
in your loop, assigning the handlers in a loop like that will not work anymore, because index
for every handler will refer to the last dropdown (because index will now be global within the function's context and not local for every loop instance).