So, I am wondering if it is possible to make the dropdown menu only have 10 visible links, and the rest would be invisible. If it ain't possible, is it possible to make it so you can only se 10 and scroll down. Any suggestions?
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
function filterFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
div = document.getElementById("myDropdown");
a = div.getElementsByTagName("a");
for (i = 0; i < a.length; i++) {
if (a[i].innerHTML.toUpperCase().indexOf(filter) > -1) {
a[i].style.display = "";
} else {
a[i].style.display = "none";
}
}
}
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover, .dropbtn:focus {
background-color: #3e8e41;
}
#myInput {
border-box: box-sizing;
background-image: url('searchicon.png');
background-position: 14px 12px;
background-repeat: no-repeat;
font-size: 16px;
padding: 14px 20px 12px 45px;
border: none;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f6f6f6;
min-width: 230px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {background-color: #ddd}
.show {display:block;}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
<input type="text" placeholder="Search.." id="myInput" onkeyup="filterFunction()">
About
Base
Blog
Contact
Custom
Support
Tools
About
Base
Blog
Contact
Custom
Support
Tools
About
Base
Blog
Contact
Custom
Support
Tools
</div>
</div>
EDIT: New answer:
I misinterpreted the question. You can slightly modify your filter function to keep track of shown items (10) and then just call it once whenever you open the menu. This way you're showing max 10 items when opening the menu and when filtering. fiddle: https://jsfiddle.net/d3kta5sw/
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
filterFunction();
}
function filterFunction() {
var input, filter, ul, li, a, i,
elementsToShow = 10,
elementsShowing = 0;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
div = document.getElementById("myDropdown");
a = div.getElementsByTagName("a");
for (i = 0; i < a.length; i++) {
if (a[i].innerHTML.toUpperCase().indexOf(filter) > -1 &&
elementsShowing < elementsToShow) {
a[i].style.display = "";
elementsShowing++;
} else {
a[i].style.display = "none";
}
}
}
Old Answer (only works for first 10 visible items):
You can do this in pure css. Try adding the following, this will hide the 11th 'a' element and onwards:
.dropdown-content a:nth-of-type(n+11) {
display:none;
}
You could add the height values of the first 10 items and set that manually in CSS or you can use Javascript count the first 10 items and add their heights together. As it is now they all have the same height so you could do h*10 but if for some reason an item breaks to a second line your height would be off. I've updated your snipped.
I've updated the myFunction function. You'll notice I add the show class before calculating the height as offsetHeight will always return 0 if the parent is hidden.
Hiding When Clicking off Button
We can handle this with the blur event. Rather than using an attribute for the event like the onclick we're going to handle this solely with JS.
Returning to Top of Dropdown
In order to return to the top of the dropdown after you click out of the dropdown we need to use the scrollTop property. in myFunction() the last line we set scrollTop = 0 on the dropDown element which scrolls us to the top!
var btn = document.querySelector('.dropbtn');
btn.addEventListener('blur', function() {
var dd = document.querySelector('.dropdown-content');
if ( dd.classList.contains('show') ) {
dd.classList.remove('show');
}
});
function myFunction() {
var dropDown = document.getElementById('myDropdown'),
items = dropDown.children,
height = 0;
dropDown.classList.toggle('show');
for (var i = 1; i < 10; i++) {
height += items[i].offsetHeight;
}
dropDown.style.height = height + 'px';
dropDown.scrollTop = 0;
}
function filterFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
div = document.getElementById("myDropdown");
a = div.getElementsByTagName("a");
for (i = 0; i < a.length; i++) {
if (a[i].innerHTML.toUpperCase().indexOf(filter) > -1) {
a[i].style.display = "";
} else {
a[i].style.display = "none";
}
}
}
var btn = document.querySelector('.dropbtn');
btn.addEventListener('blur', function() {
var dd = document.querySelector('.dropdown-content');
if ( dd.classList.contains('show') ) {
dd.classList.remove('show');
}
});
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
#myInput {
border-box: box-sizing;
background-image: url('searchicon.png');
background-position: 14px 12px;
background-repeat: no-repeat;
font-size: 16px;
padding: 14px 20px 12px 45px;
border: none;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f6f6f6;
min-width: 230px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {
background-color: #ddd
}
.show {
display: block;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
<input type="text" placeholder="Search.." id="myInput" onkeyup="filterFunction()">
About
Base
Blog
Contact
Custom
Support
Tools
About
Base
Blog
Contact
Custom
Support
Tools
About
Base
Blog
Contact
Custom
Support
Tools
</div>
</div>
CSS option:
.show{
overflow:overlay: //to hide to the other elements
height:200px; //to show desired number of elements
}
Better to use this element:
.dropdown-content
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Using Javascript I am creating a list website (as a side-project).
I use the code:
var myNodelist = document.getElementsByTagName("LI");
and that works, but
localStorage.setItem("myNodelist", document.getElementsByTagName("LI"));
doesn't. it just returns [object HTMLCollection]. Does anyone know why?
// Create a "close" button and append it to each list item
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
// Click on a close button to hide the current list item
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('ul');
list.addEventListener('click', function(ev) {
if (ev.target.tagName === 'LI') {
ev.target.classList.toggle('checked');
}
}, false);
// Create a new list item when clicking on the "Add" button
function newElement() {
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
if (inputValue === '') {
alert("You must write something!");
} else {
document.getElementById("myUL").appendChild(li);
}
document.getElementById("myInput").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
margin: 0;
min-width: 250px;
}
/* Include the padding and border in an element's total width and height */
* {
box-sizing: border-box;
}
/* Remove margins and padding from the list */
ul {
margin: 0;
padding: 0;
}
/* Style the list items */
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
list-style-type: none;
background: #eee;
font-size: 18px;
transition: 0.2s;
/* make the list items unselectable */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Set all odd list items to a different color (zebra-stripes) */
ul li:nth-child(odd) {
background: #f9f9f9;
}
/* Darker background-color on hover */
ul li:hover {
background: #ddd;
}
/* When clicked on, add a background color and strike out text */
ul li.checked {
background: #888;
color: #fff;
text-decoration: line-through;
}
/* Add a "checked" mark when clicked on */
ul li.checked::before {
content: '';
position: absolute;
border-color: #fff;
border-style: solid;
border-width: 0 2px 2px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 15px;
width: 7px;
}
/* Style the close button */
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.close:hover {
background-color: #168e00;
color: white;
}
/* Style the header */
.header {
background-color: #168e00;
padding: 30px 40px;
color: white;
text-align: center;
}
/* Clear floats after the header */
.header:after {
content: "";
display: table;
clear: both;
}
/* Style the input */
input {
margin: 0;
border: none;
border-radius: 0;
width: 75%;
padding: 10px;
float: left;
font-size: 16px;
}
/* Style the "Add" button */
.addBtn {
padding: 10px;
width: 25%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
border-radius: 0;
}
.addBtn:hover {
background-color: #bbb;
}
</style>
</head>
<body>
<div id="myDIV" class="header">
<h2 style="margin:5px">Groceries:</h2>
<input type="text" id="myInput" placeholder="Title...">
<span onclick="newElement()" class="addBtn">Add</span>
</div>
<ul id="myUL">
</ul>
</body>
</html>
If you write var Lists = document.getElementsByTagName("List"); in your console.log(list) you will see the list of elements that you need right ?
The console.log also shows array the same way ,each element of an array is print to the log without you having to write a for() loop.
However if you want to use the array you have to write the for loop
[object HTMLCollection]
means that there is an array of HTML objects, To work with the data you have to use a for loop or array methods so before storing it in local storage
Try Make an array with the object collection with
var arr = Array.from(htmlCollection);
Then save as is or convert to json string with
var myJsonString = JSON.stringify(arr);
I trust this helps
First: its better if you use id to find the dom element from DOM API.
Second: you need to use .innerText to access the text content of list item.
<ul>
<li id="item">hello</li>
</ul>
localStorage.setItem("myNodelist",document.getElementById("item").innerText);
I'm following this guide to create Search/Filter Dropdown.
But I have this method 'allNameMuseums()', that returns an array of names (for example :
array = ["Jack", "Paul", "George"]
My JS code :
async function allNameMuseums() {
let nomeFile = "dati_musei_infovis.csv";
let data3 = await d3.dsv(";", nomeFile, function (d) {
return {
Museo: d.Museo,
Ingresso: d.Ingresso,
Anno: d.Anno,
Mese: d.Mese,
Visitatori: d.Visitatori
};
});
return filtraggioNomeMuseo(data3);
};
function filtraggioNomeMuseo(data) {
array_filtrato = [];
var map = {};
//var visitatori = 0;
for (i=0; i<data.length; i++) {
if (!(array_filtrato.includes(data[i].Museo))) {
array_filtrato.push(data[i].Museo)
}
}
return array_filtrato;
}
I want to put these names instead of About, Base, Blog etc...
You could loop through the returned array and append the names as anchors to the dropdown like :
document.addEventListener("DOMContentLoaded", function(event) {
allNameMuseums().forEach(function(item){
document.getElementById("myDropdown").innerHTML += ''+item+'';
})
});
NOTE: Put your code inside DOMContentLoaded event listener to make sure all the DOM elements are loaded before executing your code/
Working sample:
document.addEventListener("DOMContentLoaded", function(event) {
allNameMuseums().forEach(function(item) {
document.getElementById("myDropdown").innerHTML += '' + item + '';
})
});
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
function filterFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
div = document.getElementById("myDropdown");
a = div.getElementsByTagName("a");
for (i = 0; i < a.length; i++) {
if (a[i].innerHTML.toUpperCase().indexOf(filter) > -1) {
a[i].style.display = "";
} else {
a[i].style.display = "none";
}
}
}
function allNameMuseums() {
return ["Jack", "Paul", "George"];
}
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
#myInput {
border-box: box-sizing;
background-image: url('searchicon.png');
background-position: 14px 12px;
background-repeat: no-repeat;
font-size: 16px;
padding: 14px 20px 12px 45px;
border: none;
border-bottom: 1px solid #ddd;
}
#myInput:focus {
outline: 3px solid #ddd;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f6f6f6;
min-width: 230px;
overflow: auto;
border: 1px solid #ddd;
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {
background-color: #ddd;
}
.show {
display: block;
}
<h2>Search/Filter Dropdown</h2>
<p>Click on the button to open the dropdown menu, and use the input field to search for a specific dropdown link.</p>
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
<input type="text" placeholder="Search.." id="myInput" onkeyup="filterFunction()">
</div>
</div>
I have a dropdown menu that does not work properly. When i click one of the buttons, a dropdown menu will appear. But when i click the button again it should close, but it dosn't. I know it has something to do with closeAll function, but i still need that function to close another dropdown menu when the first one is already open.
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
closeAll();
document.getElementById("myDropdown").classList.toggle("show");
}
function myFunction2() {
closeAll();
document.getElementById("myDropdown2").classList.toggle("show");
}
function closeAll(){
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
openDropdown.classList.remove('show');
}
}
// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
/* Dropdown Button */
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover, .dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 150px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
#myDropdown a:hover {background-color: #f1f1f1}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content
container when the user clicks on the dropdown button) */
.show {display:block;}
#myDropdown2{
min-width:200px;
border:4px solid red;
}
#myDropdown2 a:hover{
color:red;
}
.left-bar{
float:left;
}
.right-bar{
float:left;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
<div class="dropdown">
<button onclick="myFunction2()" class="dropbtn">Dropdown</button>
<div id="myDropdown2" class="dropdown-content">
<div class="left-bar">
Link 1
Link 2
Link 3
</div>
<div class="right-bar">
Link 1
Link 2
Link 3
</div>
</div>
</div>
your Functions (myFunction() and myFunction2()) first close all dropdown menu using closeAll(); and next line document.getElementById("myDropdown").classList.toggle("show"); shows it again.So,when you click the button againŲ It does not close.
For Fix it :
Just remove Function closeAll(); and change your code Like this :
function myFunction() {
document.getElementById("myDropdown2").classList.remove("show");
document.getElementById("myDropdown").classList.toggle("show");
}
function myFunction2() {
document.getElementById("myDropdown").classList.remove("show");
document.getElementById("myDropdown2").classList.toggle("show");
}
Full code :
function myFunction() {
document.getElementById("myDropdown2").classList.remove("show");
document.getElementById("myDropdown").classList.toggle("show");
}
function myFunction2() {
document.getElementById("myDropdown").classList.remove("show");
document.getElementById("myDropdown2").classList.toggle("show");
}
// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 150px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
#myDropdown a:hover {
background-color: #f1f1f1
}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content
container when the user clicks on the dropdown button) */
.show {
display: block;
}
#myDropdown2 {
min-width: 200px;
border: 4px solid red;
}
#myDropdown2 a:hover {
color: red;
}
.left-bar {
float: left;
}
.right-bar {
float: left;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
<div class="dropdown">
<button onclick="myFunction2()" class="dropbtn">Dropdown</button>
<div id="myDropdown2" class="dropdown-content">
<div class="left-bar">
Link 1
Link 2
Link 3
</div>
<div class="right-bar">
Link 1
Link 2
Link 3
</div>
</div>
</div>
Remove this Function for myFunction() & myFunction2() closeAll();
you already use ToggleClass
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
function myFunction2() {
document.getElementById("myDropdown2").classList.toggle("show");
}
function closeAll() {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
openDropdown.classList.remove('show');
}
}
// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
/* Dropdown Button */
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 150px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
#myDropdown a:hover {
background-color: #f1f1f1
}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content
container when the user clicks on the dropdown button) */
.show {
display: block;
}
#myDropdown2 {
min-width: 200px;
border: 4px solid red;
}
#myDropdown2 a:hover {
color: red;
}
.left-bar {
float: left;
}
.right-bar {
float: left;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
<div class="dropdown">
<button onclick="myFunction2()" class="dropbtn">Dropdown</button>
<div id="myDropdown2" class="dropdown-content">
<div class="left-bar">
Link 1
Link 2
Link 3
</div>
<div class="right-bar">
Link 1
Link 2
Link 3
</div>
</div>
</div>
The problem is that after you call closeAll(), you then toggle the dropdown that the user clicked on, which opens that one again.
You need to test whether the current one is already open, and not re-open it.
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
var isOpen = document.getElementById("myDropdown").classList.contains("show");
closeAll();
if (!isOpen) {
document.getElementById("myDropdown").classList.add("show");
}
}
function myFunction2() {
var isOpen = document.getElementById("myDropdown2").classList.contains("show");
closeAll();
if (!isOpen) {
document.getElementById("myDropdown2").classList.toggle("show");
}
}
function closeAll() {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
openDropdown.classList.remove('show');
}
}
// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
/* Dropdown Button */
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 150px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
#myDropdown a:hover {
background-color: #f1f1f1
}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content
container when the user clicks on the dropdown button) */
.show {
display: block;
}
#myDropdown2 {
min-width: 200px;
border: 4px solid red;
}
#myDropdown2 a:hover {
color: red;
}
.left-bar {
float: left;
}
.right-bar {
float: left;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
<div class="dropdown">
<button onclick="myFunction2()" class="dropbtn">Dropdown</button>
<div id="myDropdown2" class="dropdown-content">
<div class="left-bar">
Link 1
Link 2
Link 3
</div>
<div class="right-bar">
Link 1
Link 2
Link 3
</div>
</div>
</div>
Try this: remove the classshowof another dropdown when hasClass of show element clicked dropdown .because each time of you click closeAll was remove the show in all dropdown .So you could validate only remove the hasClass ofshow element .It prevent the toggle event of dropdown also
Array.prototype.indexOf.call(document.getElementById("myDropdown").classList, 'show')
Its used to find the hasClass
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
if(Array.prototype.indexOf.call(document.getElementById("myDropdown").classList, 'show')){
document.getElementById("myDropdown").classList.toggle("show");
document.getElementById("myDropdown2").classList.remove("show");
}
else{
closeAll();
}
}
function myFunction2() {if(Array.prototype.indexOf.call(document.getElementById("myDropdown2").classList, 'show')){
document.getElementById("myDropdown2").classList.toggle("show");
document.getElementById("myDropdown").classList.remove("show");
}
else{
closeAll()
}
}
function closeAll() {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
openDropdown.classList.remove('show');
}
}
// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
/* Dropdown Button */
.dropbtn {
background-color: #4CAF50;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover,
.dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 150px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
/* Change color of dropdown links on hover */
#myDropdown a:hover {
background-color: #f1f1f1
}
/* Show the dropdown menu (use JS to add this class to the .dropdown-content
container when the user clicks on the dropdown button) */
.show {
display: block;
}
#myDropdown2 {
min-width: 200px;
border: 4px solid red;
}
#myDropdown2 a:hover {
color: red;
}
.left-bar {
float: left;
}
.right-bar {
float: left;
}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</div>
<div class="dropdown">
<button onclick="myFunction2()" class="dropbtn">Dropdown</button>
<div id="myDropdown2" class="dropdown-content">
<div class="left-bar">
Link 1
Link 2
Link 3
</div>
<div class="right-bar">
Link 1
Link 2
Link 3
</div>
</div>
</div>
In the first step you close all dropdowns and after that toggle the current one which then will be reopened. If you want to change this behaviour you have to change the closeAll() function to receive one parameter which would be the current dropdown or button and only close all but this one.
closeAll(currentDropdown){
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if(openDropdown != currentDropdown){
openDropdown.classList.remove('show');
}
}
}
You could save the states the elements should have in an array and apply all these every time one is clicked.
// executed once on page load
var dropdowns = new array();
var tmpdropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < tmpdropdowns.length; i++) {
dropdowns[tmpdropdowns[i].id] = 0;
}
// executed on click of one button
for (i = 0; i < dropdowns.length; i++) {
dropdowns[i] = 0;
}
dropdowns[/*clicked id*/] = (dropdowns[/*clicked id*/] + 1) % 2;
for (var key in dropdowns) {
if(dropdowns[key] == 0) {
document.getElementById[key].classList.remove("show");
} else {
document.getElementById[key].classList.add("show");
}
}
I was watching a tutorial that used jQuery and wanted to turn it into JS, but my code is broken - was hoping someone could help me with this:
Tutorial JS:
$(function() {
var btn = $('button');
var progressBar = $('.progressbar');
btn.click(function() {
progressBar.find('li.active').next().addClass('active');
})
})
Taken from URL:http://www.kodhus.com/kodity/codify/kod/mGXAtb
Here is my failed attempt at rewriting the jQuery using JavaScript DOM:
var btn1 = document.getElementsByTagName('BUTTON');
var progBar = document.getElementsByClassName('progressbar');
function clickMe1() {
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
return emlClass.nextElementSibling.addClass('active');
}
btn1.addEventListener("click", clickMe1, false);
where did I go wrong?
Working fiddle.
Your code will work after several changes check the notes below :
You've missed addClass() there it's a jQuery function, for vanilla JS use .classList.add() instead:
return emlClass.nextElementSibling.classList.add("active");
querySelectorAll(); will return a list of nodes you have to loop through them and add class, use :
var emlClass = progBar.querySelectorAll("li.active");
Instead of :
var elm = progBar.querySelectorAll("li");
var emlClass = elm.querySelector(".active");
Then loop and add active class:
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
getElementsByTagName() and getElementsByClassName() will also returns a list of nodes with given name, you have to specify which one you want to pick (selecting the first in my example) :
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
Hope this helps.
var btn1 = document.getElementsByTagName('BUTTON')[0];
var progBar = document.getElementsByClassName('progressbar')[0];
function clickMe1() {
var emlClass = progBar.querySelectorAll("li.active");
for(var i=0;i<emlClass.length;i++){
emlClass[i].nextElementSibling.classList.add("active");
}
}
btn1.addEventListener("click", clickMe1, false);
.container {
width: 100%;
}
.progressbar {
counter-reset: step;
margin: 0;
margin-top: 50px;
padding: 0;
}
.progressbar li {
list-style-type: none;
float: left;
width: 33.33%;
position: relative;
text-align: center;
}
.progressbar li:before {
content: counter(step);
counter-increment: step;
width: 30px;
height: 30px;
line-height: 30px;
border: 2px solid #ddd;
display: block;
text-align: center;
margin: 0 auto 10px auto;
border-radius: 50%;
background-color: white;
}
.progressbar li:after {
content: '';
position: absolute;
width: 100%;
height: 2px;
background-color: #ddd;
top: 15px;
left: -50%;
z-index: -1;
}
.progressbar li:first-child:after {
content: none;
}
.progressbar li.active {
color: green;
}
.progressbar li.active:before {
border-color: green;
}
.progressbar li.active + li:after {
background-color: green;
}
button {
position: relative;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 2px;
left: 50%;
margin-top: 30px;
transform: translate(-50%);
cursor: pointer;
outline: none;
}
button:hover {
opacity: 0.8;
}
<div class="container">
<ul class="progressbar">
<li class="active">Step 1</li>
<li>Step 2</li>
<li>Step 3</li>
</ul>
</div>
<button>Next step</button>
.querySelectorAll("li") will return an array (or an array-like object) with one or more <li> tags. So you need to either:
loop through every <li> in that list and do the rest,
or just take the first item from that list if you don't want to worry about there being more than one li in the page,
or use .querySelector (not .querySelectorAll) to just take the first <li> for you.
MDN
I'm quite new with css. I want hold the ul visible when hovering from parent to ul. I don't know how do it.
HTML Markup
<drop-down class="dropdown">
<span>Dropdown menu<i class="fa fa-cog"></i></span>
<ul>
<li>
Github<i class="fa fa-github"></i>
</li>
<li>
BitBucket<i class="fa fa-bitbucket"></i>
</li>
<li>
Dropbox<i class="fa fa-dropbox"></i>
</li>
<li>
Google drive<i class="fa fa-google"></i>
</li>
</ul>
</drop-down>
CSS
drop-down {
background-color: #e9e9e9;
border: 1px solid #d2c2c2;
border-radius: 2px;
display: flex;
flex-flow: column nowrap;
height: 40px;
justify-content: center;
position: relative;
width: 160px;
}
drop-down:hover { cursor: pointer; }
drop-down > span {
align-items: center;
color: #555;
display: flex;
font-family: 'segoe ui';
font-size: .9rem;
justify-content: space-between;
padding: 0px .75rem;
pointer-events: none;
}
drop-down > span > i {
color: inherit;
}
drop-down ul {
background-color: #e9e9e9;
border: 1px solid #d2c2c2;
border-radius: 2px;
box-shadow: 0px 2px 5px 1px rgba(0,0,0,.15);
display: block;
right: 10%;
list-style: none;
padding: .5rem 0;
position: absolute;
opacity: 0;
pointer-events: none;
visibility: hidden;
top: 160%;
transition: all .2s ease-out;
width: 100%;
z-index: 999;
}
drop-down ul > li {
color: #555;
display: block;
}
drop-down ul > li:hover {
background-color: #007095;
color: rgba(255,255,255,.9);
}
drop-down ul > li > a {
align-items: center;
color: inherit;
display: flex;
font-family: 'segoe ui';
font-size: .95rem;
justify-content: space-between;
padding: .5rem .75rem;
text-decoration: none;
}
drop-down ul > li > a > i {
color: inherit;
}
drop-down:focus {
outline: none;
}
drop-down:hover ul {
pointer-events: auto;
opacity: 1;
top: 120%;
visibility: visible;
}
You can see it running at this fiddle: http://jsfiddle.net/vt1y9ruo/1/
I can do it with javascript, but I don't want use it for something small.
Here's a working fiddle: http://jsfiddle.net/vt1y9ruo/8/
It works by inserting an invisible bridge between the button and the list.
drop-down:hover ul, #ulwrap:hover ul {
pointer-events: auto;
opacity: 1;
top:120%;
visibility: visible;
}
#ulwrap {
display: block;
height:0;
width:100%;
position:absolute;
}
drop-down:hover #ulwrap, #ulwrap:hover {
height:100px;
}
if you want to do this using the hover feature of css, the gap between the button and the list is what's killing you. either remove this gap or use js
on a side note there is no harm in using js for something small, this is what its used for, just make it nice and reusable
Well, pure css solution (many thanks #JBux) is a little dirty (mark up). I finally go for JS solution and for this, created a custom tag:
const helper = new Helper(); // helper functions
var ddProto = Object.create(HTMLElement.prototype);
ddProto.properties = {
list: null,
options: null,
value: null,
icon: null,
index: -1,
};
ddProto.initEvents = function() {
var self = this;
// mouse over button
this.addEventListener('mouseover', function(e) {
if(!helper.hasClass(this, 'dropdown-active'))
helper.addClass(this, 'dropdown-active');
});
// mouseleave over button
this.addEventListener('mouseleave', function(e){
var rect = this.getBoundingClientRect();
var left = e.pageX;
var bottom = e.pageY;
// if mouse is out of X axis of button and if mouse is
// out (only of top) of Y axis of button, hide ul
if(left < rect.left || left >= rect.right || bottom < rect.top) {
helper.delClass(this, 'dropdown-active');
}
});
// list loses hover
this.properties.list.addEventListener('mouseleave', function(e) {
if(helper.hasClass(self, 'dropdown-active'))
helper.delClass(self, 'dropdown-active');
});
// elements click
[].forEach.call(this.properties.options, function(e) {
e.addEventListener('click', function(event){
event.preventDefault();
// set the text of selected value to button
helper.text(self.properties.value, e.innerText);
// set the position of selected value
self.properties.index = helper.position(e.parentNode);
// set the <i> class name to the button (fontawesome)
self.properties.icon.className = this.children[0].className;
// hide ul
helper.delClass(self,'dropdown-active');
},true);
});
};
ddProto.value = function() {
return this.properties.value;
};
ddProto.index = function() {
return this.properties.index;
}
ddProto.createdCallback = function() {
this.properties.list = this.querySelector('ul');
this.properties.options = this.querySelectorAll('ul > li > a');
this.properties.value = this.querySelector('span');
this.properties.icon = this.querySelector('span > i');
this.initEvents();
};
document.registerElement('drop-down', {prototype: ddProto});
Working fiddle: http://jsfiddle.net/m2dtmr24/2/
Thank you so much.
The thing you could check is the + selector (more here)
In short it lets you add styles to elements right next to each other. The actual css might look something like this:
.dropdown{
display: none;
}
.button:hover+.dropdown{
display: block;
}
This will only work when .dropdown is directly below .button in the DOM
The animation might be harder, but you could achieve something similar by for example using transition on opacity, and toggle opacity instead of display