I am having trouble trying to work out why when clicking the dropdown arrow too quickly the options in the dropdown will remain even after it has closed.
HTML
<div class="dropdown-container">
<div class="dropdown-header">
<h5 class="js-title-hook dropdown-title">
Option 1
</h5>
<div class="toggle-button">
<p>
↓
</p>
</div>
</div>
<div class="dropdown-options">
<ul class="dropdown-options-list">
<li class="js-hook-dropdown-list" data-title="Option 1">Option 1</li>
<li class="js-hook-dropdown-list" data-title="Option 2">Option 2</li>
<li class="js-hook-dropdown-list" data-title="Option 3">Option 3</li>
<li class="js-hook-dropdown-list" data-title="Option 4">Option 4</li>
<li class="js-hook-dropdown-list" data-title="Option 5">Option 5</li>
</ul>
</div>
</div>
CSS
.dropdown-container{
width: 400px;
font-family: 'helvetica';
color: 2b2b2b;
border-bottom: 1px solid #2b2b2b;
}
.dropdown-title{
float: left;
margin-right: 20px;
}
.toggle-button{
display: inline-block;
cursor: pointer;
transform: rotate(0deg);
}
.dropdown-options{
/* padding-top: 30px; */
}
.dropdown-options{
visibility: hidden;
opacity: 0;
transition: height 1s, visibility 0.5s, opacity 0.5s ease-out;
}
.dropdown-options-list{
list-style: none;
}
.dropdown-options-list li{
margin-bottom: 5px;
cursor: pointer;
}
.dropdown-options-list li:hover{
color: #D62727;
}
JavaScript
(function(){
//Incase anything ever changes in the DOM
var DOMstrings = {
dropPointer: '.toggle-button',
pageTitle: '.js-title-hook',
dropOptions: '.dropdown-options',
dropTitle: '.project-dropdown-title',
listItems: '.js-hook-dropdown-list',
}
var dropPointer = document.querySelector(DOMstrings.dropPointer);
var dropOptions = document.querySelector(DOMstrings.dropOptions);
var dropTitle = document.querySelector(DOMstrings.dropTitle);
var height = dropOptions.clientHeight;
var width = dropOptions.clientWidth;
//initisualise the height of drop options
dropOptions.style.height = '0';
// console.log(height + ' x ' + width);
dropDown();
function dropDown(){
dropPointer.addEventListener('click', function(){
//toggle for the pointer rotating
if(dropPointer.style.transform !== "rotate(180deg)"){
dropPointer.style.transform = "rotate(180deg)";
setTimeout(function(){
dropOptions.style.height = height + 'px';
dropOptions.style.marginBottom = '10px';
}, 150)
setTimeout(function(){
dropOptions.style.visibility = 'visible';
dropOptions.style.opacity = '1';
}, 700)
// console.log(height + ' x ' + width);
} else {
closeDropdown();
}
});
}
function closeDropdown() {
dropPointer.style.transform = "rotate(0deg)";
dropOptions.style.visibility = 'hidden';
dropOptions.style.opacity = '0';
setTimeout(function(){
dropOptions.style.height = '0';
dropOptions.style.marginBottom = '0px';
}, 200);
setTimeout(function(){
dropTitle.style.marginBottom = "0px";
}, 500)
}
var elements = document.querySelectorAll(DOMstrings.listItems);
var title = document.querySelector(DOMstrings.pageTitle);
// console.log(listProjects);
for(var i = 0; i < elements.length; i++){
changeProject(elements[i]);
}
function changeProject(el) {
el.addEventListener('click', function(e){
var target = e.currentTarget;
// console.log(target);
title.innerHTML = target.dataset.title;
closeDropdown();
})
}
})();
The code was a little long so here is the JSfiddle that illustrates the behaviour: https://jsfiddle.net/andylyell/jkjxmLxx/
Thank you!
create a global var for the setTimeout function that make the content visible:
thistimeout = setTimeout(function(){
dropOptions.style.visibility = 'visible';
dropOptions.style.opacity = '1';
}, 700)
Use clearTimeout()
inside the closeDropdown()
function to stop the setTimeout function
function closeDropdown() {
clearTimeout(thistimeout);
dropPointer.style.transform = "rotate(0deg)";
dropOptions.style.visibility = 'hidden';
WORKING FIDDLE: https://jsfiddle.net/VLK_STUDIO/jkjxmLxx/2/
(function(){
//Incase anything ever changes in the DOM
var DOMstrings = {
dropPointer: '.toggle-button',
pageTitle: '.js-title-hook',
dropOptions: '.dropdown-options',
dropTitle: '.project-dropdown-title',
listItems: '.js-hook-dropdown-list',
}
var dropPointer = document.querySelector(DOMstrings.dropPointer);
var dropOptions = document.querySelector(DOMstrings.dropOptions);
var dropTitle = document.querySelector(DOMstrings.dropTitle);
var height = dropOptions.clientHeight;
var width = dropOptions.clientWidth;
//initisualise the height of drop options
dropOptions.style.height = '0';
// console.log(height + ' x ' + width);
dropDown();
function dropDown(){
dropPointer.addEventListener('click', function(){
//toggle for the pointer rotating
if(dropPointer.style.transform !== "rotate(180deg)"){
dropPointer.style.transform = "rotate(180deg)";
setTimeout(function(){
dropOptions.style.height = height + 'px';
dropOptions.style.marginBottom = '10px';
}, 150)
thistimeout = setTimeout(function(){
dropOptions.style.visibility = 'visible';
dropOptions.style.opacity = '1';
}, 700)
// console.log(height + ' x ' + width);
} else {
closeDropdown();
}
});
}
function closeDropdown() {
clearTimeout(thistimeout);
dropPointer.style.transform = "rotate(0deg)";
dropOptions.style.visibility = 'hidden';
dropOptions.style.opacity = '0';
setTimeout(function(){
dropOptions.style.height = '0';
dropOptions.style.marginBottom = '0px';
}, 200);
setTimeout(function(){
dropTitle.style.marginBottom = "0px";
}, 500)
}
var elements = document.querySelectorAll(DOMstrings.listItems);
var title = document.querySelector(DOMstrings.pageTitle);
// console.log(listProjects);
for(var i = 0; i < elements.length; i++){
changeProject(elements[i]);
}
function changeProject(el) {
el.addEventListener('click', function(e){
var target = e.currentTarget;
// console.log(target);
title.innerHTML = target.dataset.title;
closeDropdown();
})
}
})();
The issue is due to your setTimeout
in function dropDown()
.
If you click the dropdown button again within 700ms of opening it, the dropOptions.style.visibility = 'hidden';
line will be executed first, then the 700ms timeout will expire, so dropOptions.style.visibility = 'visible';
will then be executed – thus leaving the dropdown visible on the screen.
To fix it, inside each setTimeout
handler, check if the dropdown is still hidden/shown before modifying the properties of dragOptions
.
This is what I mean:
function dropDown(){
dropPointer.addEventListener('click', function(){
//toggle for the pointer rotating
if(dropPointer.style.transform !== "rotate(180deg)"){
dropPointer.style.transform = "rotate(180deg)";
setTimeout(function(){
if(dropPointer.style.transform !== "rotate(180deg)")return;
dropOptions.style.height = height + 'px';
dropOptions.style.marginBottom = '10px';
}, 150)
setTimeout(function(){
if(dropPointer.style.transform !== "rotate(180deg)")return;
dropOptions.style.visibility = 'visible';
dropOptions.style.opacity = '1';
}, 700)
// console.log(height + ' x ' + width);
} else {
closeDropdown();
}
});
}
function closeDropdown() {
dropPointer.style.transform = "rotate(0deg)";
dropOptions.style.visibility = 'hidden';
dropOptions.style.opacity = '0';
setTimeout(function(){
if(dropPointer.style.transform === "rotate(180deg)")return;
dropOptions.style.height = '0';
dropOptions.style.marginBottom = '0px';
}, 200);
setTimeout(function(){
if(dropPointer.style.transform === "rotate(180deg)")return;
dropTitle.style.marginBottom = "0px";
}, 500);
}
Working JSFiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With