I am trying out working with dropdown menus, and I was thinking about making a template for the dropdowns so that I can easily recreate them without any additional Javascript. However, in one of my if loops, an event.target and another element are always returning that they are different when they aren't. It doesn't make any sense, since they are the same element (proved by the console) and should be returning true. Here is the code:
const _$$ = (q) => document.getElementsByClassName(q);
let dropdowns = _$$('dropdown');
if (dropdowns[0]) {
for (let dropdown of dropdowns) {
let title = dropdown.children[0],
options;
title.setAttribute('tabindex', 0);
title.addEventListener('focus', function() {
options = Array.from(dropdown.children).slice(1, dropdown.children.length);
for (let option of options) {
option.style.display = 'block';
option.setAttribute('tabindex', options.indexOf(option) + 1);
option.style.top = `${title.offsetHeight+options.indexOf(option)*title.offsetHeight}px`;
option.style.padding = window.getComputedStyle(title, null).getPropertyValue('padding');
}
document.addEventListener('click', function(e) {
console.log(e.target);
console.log(title);
if (e.target !== dropdown || e.target !== title) {
for (let option of options) {
if (e.target !== option) {
option.style.display = 'none';
}
}
}
}, false);
}, false);
}
}
.dropdown-title {
padding: 5px 8px;
color: blue;
background: white;
width: fit-content;
}
.dropdown {
display: flex;
flex-direction: column;
}
.dropdown:hover {
cursor: pointer;
}
.dropdown-title {
outline: none;
}
.dropdown-option {
display: none;
position: absolute;
user-select: none;
}
<div class="dropdown --top-dropdown">
<div class="dropdown-title" tabindex="0">Dropdown</div>
<div class="dropdown-option" tabindex="1" style="display: none; top: 31px; padding: 5px 8px;">Dropdown Option</div>
<div class="dropdown-option" tabindex="2" style="display: none; top: 62px; padding: 5px 8px;">Dropdown Option</div>
</div>
As you can see, the e.target
and option
are the same element. However, in the if loop where it says if (e.target !== dropdown || e.target !== option) {...}
it is always saying they are different elements and removing the dropdown options.
The condition e.target !== dropdown || e.target !== title
should be changed to e.target !== dropdown && e.target !== title
. The reason for that is when e.target
equals title
, it necessarily doesn't equal dropdown
and vice versa (when e.target
is dropdown
, and when the condition is or (||
) the expression is always true
.
const _$$ = (q) => document.getElementsByClassName(q);
let dropdowns = _$$('dropdown');
if (dropdowns[0]) {
for (let dropdown of dropdowns) {
let title = dropdown.children[0],
options;
title.setAttribute('tabindex', 0);
title.addEventListener('focus', function() {
options = Array.from(dropdown.children).slice(1, dropdown.children.length);
for (let option of options) {
option.style.display = 'block';
option.setAttribute('tabindex', options.indexOf(option) + 1);
option.style.top = `${title.offsetHeight+options.indexOf(option)*title.offsetHeight}px`;
option.style.padding = window.getComputedStyle(title, null).getPropertyValue('padding');
}
document.addEventListener('click', function(e) {
if (e.target !== dropdown && e.target !== title) {
for (let option of options) {
if (e.target !== option) {
option.style.display = 'none';
}
}
}
}, false);
}, false);
}
}
.dropdown-title {
padding: 5px 8px;
color: blue;
background: white;
width: fit-content;
}
.dropdown {
display: flex;
flex-direction: column;
}
.dropdown:hover {
cursor: pointer;
}
.dropdown-title {
outline: none;
}
.dropdown-option {
display: none;
position: absolute;
user-select: none;
}
<div class="dropdown --top-dropdown">
<div class="dropdown-title" tabindex="0">Dropdown</div>
<div class="dropdown-option" tabindex="1" style="display: none; top: 31px; padding: 5px 8px;">Dropdown Option</div>
<div class="dropdown-option" tabindex="2" style="display: none; top: 62px; padding: 5px 8px;">Dropdown Option</div>
</div>