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 NavComponent extends HTMLElement {
constructor() {
super();
let template = document.currentScript.ownerDocument.querySelector('template');
let clone = document.importNode(template.content, true);
let root = this.attachShadow({ mode: 'open' });
root.appendChild(clone);
}
connectedCallback() {
let ddc = this.shadowRoot.querySelectorAll('.dropdowncontainer')
let dd = this.shadowRoot.querySelectorAll('.dropdown');
let ddc_length = ddc.length
for (let index = 0; index < ddc_length; index++) {
ddc[index].addEventListener('click', e => {
dd[index].classList.toggle('show');
});
}
/** have to update the code ............ */
window.onclick = function (event) {
} /** END - have to update the code ............ */
}
}
customElements.define('app-nav', NavComponent)
please refer this demo for complete code
The best solution, as @guitarino suggested is to define a dropdown menu custom element.
When the menu is clicked, call a (first) event handler that will show/hide the menu, and also add/remove a (second)
dropdown
event handler onwindow
.At its turn, the (second)
dropdown
event handler will call the first event handler only if the action is outside the custom element itself.It works with or without Shadow DOM:
An unrelated suggestion: you should probably separate
.dropdown
into its own<app-nav-dropdown>
component and assign the 'click' event listeners in its 'constructor' or 'connectedCallback'.The best idea for your problem is to
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 likeThere's a problem with this solution though, that if you click on the menu item again after opening it, it will call both
.dropdown
andwindow
handlers, and the net result will be that the dropdown will remain open. To fix that, you would normally add a check inhandleDropdownUnfocus
:However, it will not work. Even when you click on
.dropdown
, youre.target
will beapp-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 forlet
is very limited still, so you're more likely going to transpile. The transpiler will just change everylet
tovar
. However, if you usevar
in your loop, assigning the handlers in a loop like that will not work anymore, becauseindex
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).