How can I read the selected value of this menu, as if it were a dropdown list?
For a regular dropdown list like below, I use something like this to read the value:
<select id="ddl">
<option value="In" selected="selected">In</option>
<option value="Out">Out</option>
<option value="Ratio">Ratio</option>
</select>
With javascript I read the selected value:
var dropdown = document.getElementById("ddl");
var InOrOut = dropdown.options[dropdown.selectedIndex].value;
Is it possible to use something like this to read the selected value of the menu below:
function FillAll()
{
alert('I will read value');
// This is where menu value is read.
alert('Value read is');
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style type="text/css">
#wrapper {
width: 100%;
border: 1px solid black;
overflow: hidden; /* will contain if #first is longer than #second */
}
#first {
width: 400px;
float:left; /* add this */
border: 1px solid red;
}
#second {
border: 1px solid green;
text-align: right;
overflow: hidden; /* if you don't want #second to wrap below #first */
}
.bs-example{
margin: 20px;
}
.text
{
font-size: 15pt;
font-family: Helvetica;
color: #3d718b;
}
hr{
margin: 60px 0;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div style="float:left;">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li>Value1</li>
<li>Value2</li>
<li>Value3</li>
</ul>
</li>
</li>
</ul>
</div>
<button id="ButtonSearch" onclick="FillAll()">GO</button>
Since one can't do much to change the design of the regular dropdown list, I was thinking of using another approach, and use an html menu instead of the ddl.
Something I didn't mention is that the code to read the value would go inside the click event of a button that already exists. I didn't mention it before because I didn't know the click event would be used to read the value.
You can use getAttribute to scrape a value off of each li:
$('.dropdown-menu li').click( e => {
console.log(e.target.getAttribute('value'));
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style type="text/css">
#wrapper {
width: 100%;
border: 1px solid black;
overflow: hidden; /* will contain if #first is longer than #second */
}
#first {
width: 400px;
float:left; /* add this */
border: 1px solid red;
}
#second {
border: 1px solid green;
text-align: right;
overflow: hidden; /* if you don't want #second to wrap below #first */
}
.bs-example{
margin: 20px;
}
.text
{
font-size: 15pt;
font-family: Helvetica;
color: #3d718b;
}
hr{
margin: 60px 0;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div style="float:left;">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li value="1">Value1</li>
<li value="2">Value2</li>
<li value="3">Value3</li>
</ul>
</li>
</li>
</ul>
</div>
This looks to do what you need using either jQuery or native JS.
<script>
// with jquery
$('.dropdown-menu li').click(function(el) {
console.log(el.target.textContent)
})
// native
const list = document.querySelectorAll('.dropdown-menu li');
list.forEach(el => el.addEventListener('click', function listClick() {
console.log(el.textContent);
}));
</script>
The short answer is, yes. The following code, following your example, uses an event handler which is triggered when one of the menu items are clicked. I've also included a working jsfiddle example below.
HTML
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul class="dropdown-menu">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
</ul>
</li>
</ul>
<div class="col-xs-12 text-danger" id="result"></div>
Javascript / jQuery
$(document).on('click', '.dropdown-menu li a', function() {
var r = $('#result');
r.empty().append('You have clicked <strong>'+$(this).text()+'</strong> in the drop-down menu.');
});
https://jsfiddle.net/Xonos/z9jfa86r/
UPDATE: I have added another answer which shows a secondary example where you can select/de-select a menu item and then click a button to determine which of the menu items are selected. The JSFiddle link is below.
HTML
<div class="col-xs-12">
<ul class="nav nav-pills">
<li class="text" class="dropdown">
</b>
<ul id="myDropdown" class="dropdown-menu">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 text-red" id="result"> </div>
<br>
<div class="col-xs-12">
<button id="checkBtn" class="btn btn-sm btn-success pull-right">Check Selected Menu Item</button>
</div>
<div class="col-xs-12 text-orange" id="check"> </div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
.text-red {
color:rgb(206, 35, 35);
}
.text-orange {
color:rgb(252, 144, 0);
}
.nav {
background-color:rgba(255,255,255,0.15);
}
.selected-item {
background-color:rgb(255,0,0);
}
Javascript / jQuery
$(document).on('click', '#myDropdown li a', function() {
var r = $('#result');
$(this).parent().parent().children().removeClass('selected-item');
if($(this).hasClass('selected-item')) {
$(this).removeClass('selected-item'); //De-select menu item.
} else {
$(this).parent().addClass('selected-item'); //Select menu item.
}
r.empty().append('You have selected <strong>'+$(this).text()+'</strong> in the drop-down menu.');
});
$(document).on('click', '#checkBtn', function() {
var selected = $('#myDropdown .selected-item');
if(selected.length > 0) { //If any of the menu items <li> have the "selected-item" class added.
$('#check').empty().append('Found a selected menu item. The value of it is: <strong>'+selected.text()+'</strong>');
} else {
$('#check').empty().append('You have not selected an item from the menu.');
}
});
https://jsfiddle.net/Xonos/74pwyL1m/
Related
I'm trying to make a search bar. No matter what I type in search box it shows the "Dropdown" as result and it doesn't show the items inside that list when I search. What am I doing wrong?
https://jsfiddle.net/5xh86fkn/
var dropdown = document.getElementsByClassName("dropdown-btn");
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", function() {
this.classList.toggle("active");
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === "block") {
dropdownContent.style.display = "none";
} else {
dropdownContent.style.display = "block";
}
});
}
function myFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("mySearch");
filter = input.value.toUpperCase();
ul = document.getElementById("myMenu");
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
<div class="sidenav">
<input type="text" id="mySearch" onkeyup="myFunction()" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li>About</li>
<li>Services</li>
<li>Clients</li>
<li>Contact</li>
<button class="dropdown-btn">Dropdown
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-container">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</div>
<li>Search</li>
</ul>
</div>
This is a working demo of your attempt of filtering the menu items in real time by typing suggestions on the input text.
The main problem was using the correct strategy to fetch the menu items from dom. The element you wanted to partecipate in the filtering, wasn't a <LI> element.
Plus the list you embedded inside the Dropdown button wasn't included in a ol container and was breaking the correct behaviour.
I slightly refactored your html and focused on the single js function in charge of filtering the list according to the input typed:
function f(filter){
menuItems = document.querySelectorAll('#myMenu > li');
for(const menuItem of menuItems){
const textContent = menuItem.textContent.trim().toUpperCase();
//console.log(`"${textContent}" "${filter}" "${textContent.indexOf(filter)}"`);
if (textContent.indexOf(filter.toUpperCase()) > -1) {
menuItem.classList.remove('hidden');
}else{
menuItem.classList.add('hidden');
}
}
}
.hidden{
display: none;
}
body {
font-family: "Lato", sans-serif;
}
/* Fixed sidenav, full height */
.sidenav {
height: 100%;
width: 200px;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: #111;
overflow-x: hidden;
padding-top: 20px;
}
/* Style the sidenav links and the dropdown button */
.sidenav a, .dropdown-btn {
padding: 6px 8px 6px 16px;
text-decoration: none;
font-size: 20px;
color: #818181;
display: block;
border: none;
background: none;
width: 100%;
text-align: left;
cursor: pointer;
outline: none;
}
/* On mouse-over */
.sidenav a:hover, .dropdown-btn:hover {
color: #f1f1f1;
}
/* Main content */
.main {
margin-left: 200px; /* Same as the width of the sidenav */
font-size: 20px; /* Increased text to enable scrolling */
padding: 0px 10px;
}
/* Add an active class to the active dropdown button */
.active {
background-color: green;
color: white;
}
/* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
.dropdown-container {
display: none;
background-color: #262626;
padding-left: 8px;
}
/* Optional: Style the caret down icon */
.fa-caret-down {
float: right;
padding-right: 8px;
}
/* Some media queries for responsiveness */
#media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
<div class="sidenav">
<input type="text" id="mySearch" onkeyup="f(this.value)" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li>About</li>
<li>Services</li>
<li>Clients</li>
<li>Contact</li>
<li>
<button class="dropdown-btn">
Dropdown
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-container">
<ol>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ol>
</div>
</li>
<li>
Search
</li>
</ul>
</div>
For simplicity I removed code not related to the Search question.
I would suggest a slightly different approach here.
Use the textContent of the nodes so that you would not match the HTML other than that.
Leverage the data attribute and some CSS to make the code smaller by setting them to a true/false string and show/hide based upon that.
Use a descender selector to find only a that is directly inside an li by using li>a - I would strongly suggest classes instead of element selectors however for the "searchable" elements.
Note I hide the parent li by a toggle of the dataset value
I removed the JavaScript from the HTML as a best practice
Note this code can be further reduced but I left it verbose for clarity.
document.getElementById("mySearch").addEventListener('keyup', (event) => {
const findMe = event.target.value.toUpperCase();
const searchable = document.querySelectorAll('li>a');
searchable.forEach(function(searchItem) {
searchItem.parentElement.dataset.isfound = searchItem.textContent.toUpperCase().includes(findMe) ? "true" : "false";
});
});
li[data-isfound="true"] {
background-color: yellow;
}
li[data-isfound="false"] {
display: none;
}
<div class="sidenav">
<input type="text" id="mySearch" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li>About</li>
<li>Services</li>
<li>Clients</li>
<li>Contact</li>
<li><button class="dropdown-btn">Dropdown
<i class="fa fa-caret-down"></i>
</button></li>
<ul class="dropdown-container">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
<li>Search</li>
</ul>
</div>
What I am trying to do is, when I click on green element I want the purple one with the same id be removed. Now my problem is I can not loop through purple element's id and find the one which match with green one and then remove it from the DOM. I tried to use querySelectorAll but it doesn't work with addEventListener and when I use querySelector it just returns always the first element.So the goal is to remove both elements green and purple that has the same id.
if you see in HTML code inside the ul tag there is another one with the id container actually this is the problem the first ul tag with id main is the original one and the one inside it with id container it will be generated automatically with jQuery plugin if I set any new attribute to class main the class container will copy it. my goal is to click on green one and delete two elements from DOM. The one which I am clicking and another with same id. is there any way for that?
Has anyone solution for that how to remove simultaneously another element with the same id of clicked element?
document.addEventListener("DOMContentLoaded", () => {
document.querySelector("ul").addEventListener("click", getItem)
})
function getItem(e) {
let li = e.target.closest(".visible")
let span = e.target
let getID = span.attributes.id.value
console.log("This is visible element", getID)
if (li) {
li.remove()
}
}
#main {
background-color: skyblue;
}
.hidden {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #7d34eb;
}
#container {
background-color: #3483eb;
margin-top: 15px
}
.visible {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #12a370;
}
span {
position: relative;
left: 1rem;
padding: 50%;
color: red;
cursor: pointer;
}
<div class="content">
<ul id="main">
<li class="hidden">
<span id="1">A</span>
</li>
<li class="hidden">
<span id="2">B</span>
</li>
<li class="hidden">
<span id="3">C</span>
</li>
<ul id="container">
<li class="visible">
<span id="1">A</span>
</li>
<li class="visible">
<span id="2">B</span>
</li>
<li class="visible">
<span id="3">C</span>
</li>
</ul>
</ul>
</div>
I changed all your spans to div to fill up the LI element. I also changed all id to data-id, because id should be a unique.
EDIT: Based on the comment. In your original post, you added a click listener on the first UL that querySelector returns, which is #main. I made that more clear in the code. As the comment, in my answer, suggest, it's better to add a click listener to ul#container instead.
EDIT 2: Based on another comment. :P I added code for looping through and removing all elements with matching data-id.
document.addEventListener("DOMContentLoaded", () => {
document.querySelector("ul#main").addEventListener("click", getItem);
})
function getItem(e) {
let divEl = e.target;
let dataset = divEl.dataset;
let visibleLi = divEl.parentElement;
let isVisibleElement = visibleLi.classList.contains('visible');
let matchingDatasetDivs = document.querySelectorAll(`[data-id="${dataset.id}"]`);
if (isVisibleElement)
console.log("This is visible element", dataset.id);
if (isVisibleElement && matchingDatasetDivs.length) {
for (let i = 0; i < matchingDatasetDivs.length; i++) {
let containerLi = matchingDatasetDivs[i].parentElement;
containerLi.remove();
}
}
}
#main {
background-color: skyblue;
}
.hidden, .visible {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #7d34eb;
}
.visible {
background-color: #12a370;
}
#container {
background-color: #3483eb;
margin-top: 15px
}
li > div {
position: relative;
left: 1rem;
/* padding: 50%; */
color: red;
cursor: pointer;
text-align: center; /* ADDED */
}
<div class="content">
<ul id="main">
<li class="hidden">
<div data-id="1">A</div>
</li>
<li class="hidden">
<div data-id="2">B</div>
</li>
<li class="hidden">
<div data-id="3">C</div>
</li>
<ul id="container">
<li class="visible">
<div data-id="1">A</div>
</li>
<li class="visible">
<div data-id="2">B</div>
</li>
<li class="visible">
<div data-id="3">C</div>
</li>
</ul>
</ul>
</div>
In the below set of code basd on selecting the .help-menu elements on left .help-descr div navigated to particular section .
Similarly on scrolling the .help-descr div I want to add active class selection to appropriate .help-menu elements
This what I have tried:
Its something similar to the attached link Add Menu Active Class when scrolling to div I am not able to replicate same approach here
help.js
// on load of page
$(function() {
$('.backend-feature li :first').addClass('active');
$('.backend-head').addClass('active');
$('.selected-item').empty();
$('.selected-item').append('<span>Supported Features</span><i class="ion-android-arrow-dropright"></i><span>Backend</span><i class="ion-android-arrow-dropright"></i><span style="font-weight:bold;">' + $('.backend-feature li :first').text() + '</span');
});
//on click of backend feature menu
$(".backend-feature-li").on('click', function() {
$('.frontend-head').removeClass('active');
$('.frontother-head').removeClass('active');
$('.frontend-feature li').find('a').removeClass('active');
$('.front-otherfeature-li').find('a').removeClass('active');
$(this).siblings().find('a').removeClass('active');
$('.backend-head').addClass('active');
$(this).find('a').addClass('active');
$('.selected-item').empty();
$('.selected-item').append('<span>Supported Features</span><i class="ion-android-arrow-dropright"></i><span>Backend</span><i class="ion-android-arrow-dropright"></i><span style="font-weight:bold;">' + $(this).text() + '</span');
});
// on click of frontend feature menu
$(".frontend-feature-li").on('click', function() {
$('.backend-head').removeClass('active');
$('.frontother-head').removeClass('active');
$('.backend-feature li').find('a').removeClass('active');
$('.front-otherfeature-li').find('a').removeClass('active');
$(this).siblings().find('a').removeClass('active');
$('.frontend-head').addClass('active');
$(this).find('a').addClass('active');
$('.selected-item').empty();
$('.selected-item').append('<span>Supported Features</span><i class="ion-android-arrow-dropright"></i><span>Frontend</span><i class="ion-android-arrow-dropright"></i><span style="font-weight:bold;">' + $(this).text() + '</span');
});
//on click of frontend other features menu
$(".front-otherfeature-li").on('click', function() {
$('.backend-head').removeClass('active');
$('.backend-feature li').find('a').removeClass('active');
$('.frontend-feature-li').find('a').removeClass('active');
$(this).siblings().find('a').removeClass('active');
$('.frontend-head').addClass('active');
$('.frontother-head').addClass('active');
$(this).find('a').addClass('active');
$('.selected-item').empty();
$('.selected-item').append('<span>Supported Features</span><i class="ion-android-arrow-dropright"></i><span>Frontend</span><i class="ion-android-arrow-dropright"></i><span>Other Features</span><i class="ion-android-arrow-dropright"></i><span style="font-weight:bold;">' + $(this).text() + '</span');
});
.ion-help-circled {
cursor: pointer;
}
.help-row {
flex-wrap: nowrap;
max-width: 100%;
}
.help-menu {
background-color: #efefef;
overflow: auto;
padding: 15px;
height: 85vh;
}
.help-descr {
position: relative;
background-color: white;
padding: 25px 25px;
overflow: auto;
height: calc(100vh - 107px);
border: 1px solid #efefef;
}
.help-menu ul .front-otherfeature-li {
margin-left: 18px;
}
.help-menu ul li {
list-style-type: none;
margin: 8px;
}
.help-menu ul .backend-head,
.help-menu ul .frontend-head {
margin-left: 0px;
}
.backend-feature li a,
.frontend-feature li a,
.frontend-otherfeature li a {
padding: 0;
text-decoration: none;
color: black;
}
.help-menu li .active {
font-weight: bold;
}
.help-menu a:hover {
font-weight: bold;
}
.main-section {
background-color: white;
}
section {
display: flex;
flex-direction: column;
padding-bottom: 15px;
}
article {
display: flex;
flex-direction: column;
padding-left: 30px;
}
.main-section ul>li {
margin-top: 6px;
}
.main-section p {
margin-bottom: 0px;
}
.backend-feature-arrow,
.frontend-feature-arrow,
.other-feature-arrow {
margin-right: 6px;
cursor: pointer;
}
.selected-item span {
padding: 6px;
}
.descr-seclevel {
list-style-type: square;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'">
<link rel="stylesheet" href="./../node_modules/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="./css/style.css">
<link src="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" src_type="url" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="./vendors/css/ionicons.min.css">
<script defer src="./js/help_page.js"></script>
<title>Revive</title>
</head>
<body>
<div id="header">
<div class="dashboard-header">
<div class="dashboard-left-header">
<ul style="margin-bottom: 0px;">
<li>
<a style="cursor: default;" class="logo" href=""><img src="./assets/img/img1.png"></img>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="row help-row">
<div class="col-sm-3 help-menu">
<ul>
<li style="font-weight: bold;">Supported Features</li>
<li>
<ul>
<li class='backend-head'><i class="backend-feature-arrow ion-ios-arrow-down" style="font-size:18px ;display:inline-block"></i>Backend</li>
<li>
<ul class="backend-feature">
<li class="backend-feature-li">Datasources</li>
<li class="backend-feature-li">Joins</li>
</ul>
</li>
<li class='frontend-head'><i class="frontend-feature-arrow ion-ios-arrow-right" style="font-size:18px ;display:inline-block"></i>Frontend</li>
<li>
<ul class="frontend-feature">
<li class="frontend-feature-li">Properties</li>
<li class="frontother-head"><i class="other-feature-arrow ion-ios-arrow-right" style="font-size:18px ;display:inline-block"></i>Other Features</li>
<li>
<ul class="frontend-otherfeature">
<li class="front-otherfeature-li">Actions</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div class="col-sm-9 help-descr">
<div class='selected-item'></div>
<section class="main-section" id="datasource">
<header>
<h1>Datasources</h1>
</header>
<article>
<p>The supported Datasources:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Excel</li>
<li>Csv</li>
<li>Oracle Database</li>
<li>MSSQL server</li>
<li>PostgreSQL</li>
<li>MySQL</li>
</ul>
</article>
</section>
<section class="main-section" id="joins">
<header>
<h1>Joins</h1>
</header>
<article>
<p>The supported Joins:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Inner Join</li>
<li>Left Join</li>
<li>Right Join</li>
<li>Full Outer Join</li>
</ul>
</article>
</section>
<section class="main-section" id="properties">
<header>
<h1>Properties</h1>
</header>
<article>
<p>The supported Properties:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Titles on charts</li>
<li>X-axis and Y-axis Titles will be renamed</li>
<li>Text Properties like font style ,size and color</li>
<li>Background color</li>
<li>Grid lines</li>
<li>Borders for charts</li>
<li>Alias name for values</li>
<li>Legends will be enabled only if present</li>
<li>Color of Chart:</li>
<ul class="descr-seclevel" style="margin-left: 20px;">
<li>If color is applied it will be added else default color is applied</li>
<li>If a chart contains multiple color representing its data and if palate is assigned it will be applied </li>
</ul>
</ul>
</article>
</section>
<section class="main-section" id="actions">
<header>
<h1>Actions</h1>
</header>
<article>
<p>Actions supported:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Only on-select is supported</li>
<li>With Actions from one dashboard to different dashboard interacts with all charts in target dashboard</li>
</ul>
</article>
</section>
</div>
</div>
</body>
</html>
If you put an IntersectionObserver on each of the main sections the system will tell you when it comes into view or goes out of view.
Then you can add or remove the active class from the related link in the menu.
This snippet gives a demo but it had to shorten the overall length of the menu area just so we got to see the content below and it also fixed it otherwise it scrolled up and the effect of adding the active class couldn't be seen as the menu item was off the screen.
To make it obvious which section(s) are in view a lime background has been put on the link.
Note, there is some thought needed on what 'active' actually means since more than one section can be in the viewport at once. This snippet does not attempt to tackle that - it's ouside the scope of this question.
The snippet needs to be viewed full page.
const callback = (entries, observer) => {
entries.forEach(entry => {
const id = entry.target.id;
const el = document.body.querySelector('[href="#' + id + '"]');
if (entry.isIntersecting) {
el.classList.add('active');
} else {
el.classList.remove('active');
}
});
};
const sections = document.querySelectorAll('.main-section');
const options = {
threshold: 0.33
};
const observer = new IntersectionObserver(callback, options);
sections.forEach(section => {
observer.observe(section);
});
.ion-help-circled {
cursor: pointer;
}
.help-row {
flex-wrap: nowrap;
max-width: 100%;
}
.help-menu {
background-color: #efefef;
overflow: auto;
padding: 15px;
height: 85vh;
height: 30vh;
/* changed for demo so we can see stuff */
}
.help-descr {
position: relative;
background-color: white;
padding: 25px 25px;
overflow: auto;
height: calc(100vh - 107px);
border: 1px solid #efefef;
}
.help-menu ul .front-otherfeature-li {
margin-left: 18px;
}
.help-menu ul li {
list-style-type: none;
margin: 8px;
}
.help-menu ul .backend-head,
.help-menu ul .frontend-head {
margin-left: 0px;
}
.backend-feature li a,
.frontend-feature li a,
.frontend-otherfeature li a {
padding: 0;
text-decoration: none;
color: black;
}
.help-menu li .active {
font-weight: bold;
background-color: lime;
/* ADDED JUST FOR DEMO */
}
.help-menu a:hover {
font-weight: bold;
}
.main-section {
background-color: white;
}
section {
display: flex;
flex-direction: column;
padding-bottom: 15px;
}
article {
display: flex;
flex-direction: column;
padding-left: 30px;
}
.main-section ul>li {
margin-top: 6px;
}
.main-section p {
margin-bottom: 0px;
}
.backend-feature-arrow,
.frontend-feature-arrow,
.other-feature-arrow {
margin-right: 6px;
cursor: pointer;
}
.selected-item span {
padding: 6px;
}
.descr-seclevel {
list-style-type: square;
}
<div style="position: fixed; z-index: 1;">
<!-- added just for demo -->
<div id="header">
<div class="dashboard-header">
<div class="dashboard-left-header">
<ul style="margin-bottom: 0px;">
<li>
<a style="cursor: default;" class="logo" href=""><img src="./assets/img/img1.png"></img>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="row help-row">
<div class="col-sm-3 help-menu">
<ul>
<li style="font-weight: bold;">Supported Features</li>
<li>
<ul>
<li class='backend-head'><i class="backend-feature-arrow ion-ios-arrow-down" style="font-size:18px ;display:inline-block"></i>Backend</li>
<li>
<ul class="backend-feature">
<li class="backend-feature-li">Datasources</li>
<li class="backend-feature-li">Joins</li>
</ul>
</li>
<li class='frontend-head'><i class="frontend-feature-arrow ion-ios-arrow-right" style="font-size:18px ;display:inline-block"></i>Frontend</li>
<li>
<ul class="frontend-feature">
<li class="frontend-feature-li">Properties</li>
<li class="frontother-head"><i class="other-feature-arrow ion-ios-arrow-right" style="font-size:18px ;display:inline-block"></i>Other Features</li>
<li>
<ul class="frontend-otherfeature">
<li class="front-otherfeature-li">Actions</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<!--ADDED -->
<div class="col-sm-9 help-descr">
<div class='selected-item'></div>
<section class="main-section" id="datasource">
<header>
<h1>Datasources</h1>
</header>
<article>
<p>The supported Datasources:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Excel</li>
<li>Csv</li>
<li>Oracle Database</li>
<li>MSSQL server</li>
<li>PostgreSQL</li>
<li>MySQL</li>
</ul>
</article>
</section>
<section class="main-section" id="joins">
<header>
<h1>Joins</h1>
</header>
<article>
<p>The supported Joins:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Inner Join</li>
<li>Left Join</li>
<li>Right Join</li>
<li>Full Outer Join</li>
</ul>
</article>
</section>
<section class="main-section" id="properties">
<header>
<h1>Properties</h1>
</header>
<article>
<p>The supported Properties:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Titles on charts</li>
<li>X-axis and Y-axis Titles will be renamed</li>
<li>Text Properties like font style ,size and color</li>
<li>Background color</li>
<li>Grid lines</li>
<li>Borders for charts</li>
<li>Alias name for values</li>
<li>Legends will be enabled only if present</li>
<li>Color of Chart:</li>
<ul class="descr-seclevel" style="margin-left: 20px;">
<li>If color is applied it will be added else default color is applied</li>
<li>If a chart contains multiple color representing its data and if palate is assigned it will be applied </li>
</ul>
</ul>
</article>
</section>
<section class="main-section" id="actions">
<header>
<h1>Actions</h1>
</header>
<article>
<p>Actions supported:</p>
<ul class="descr-firstlevel" style="margin-left: 20px;">
<li>Only on-select is supported</li>
<li>With Actions from one dashboard to different dashboard interacts with all charts in target dashboard</li>
</ul>
</article>
</section>
</div>
</div>
I got the code from w3scgool and modified it. The dropdown menu opens but when I click inside of it - submenu, then it closes. Here is the pure JavaScript code.
var dropdown = document.getElementsByClassName('dropdown-btn');
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener('click', function() {
this.classList.toggle('active');
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === 'block') {
dropdownContent.style.display = 'none';
} else {
dropdownContent.style.display = 'block';
}
});
}
nav.side-nav {
order: 0;
display: flex;
flex: 1 1;
flex-direction: column;
align-self: stretch;
margin-bottom: 0.67rem;
}
nav.side-nav ul {
margin: 0;
}
nav.side-nav li {
border-bottom: 1px solid #d9dadc;
border-left: 1px solid #d9dadc;
border-right: 1px solid #d9dadc;
list-style: none;
padding: 5px 15px;
font-size: 17px;
line-height: 24px;
}
nav.side-nav li:first-child {
background: #092a31;
color: white;
border: none;
font-size: 20px;
padding: 15px;
line-height: 1.1;
}
nav.side-nav li:not(:first-child):hover {
background: #cda600;
color: white;
cursor: pointer;
}
/*dropdown menu*/
.dropdown-container {
display: none;
background-color: #ffffff;
padding-left: 8px;
}
<html>
<nav class="side-nav">
<ul>
<li style="text-align:left;">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li id="navDrop" class="dropdown-btn">
Menu</li>
<div class="dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br>
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br>
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br>
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
<li href="#">Menu</li>
</ul>
</nav>
</html>
I am new to JS. Could someone navigate/show how to edit the code to prevent dropdown from closing when click on its submenu.
Update: took out the onclick feature. Took from my code too.
Any suggestions about the code because it stays the same. In this case I am using just JS without jquery library.
After making the modifications suggested by #Heretic Monkey and #Ganesh chaitanya, you can simplify your code by using map() instead of a for loop, and again classList.toggle() instead of else if.
just modify your css a little with a new class that you add to your div. Like that
var dropdown = document.getElementsByClassName("dropdown-btn");
// here dropdown.map() don't work, use
Array.prototype.map.call(dropdown, function(drop) {
drop.addEventListener("click", function() {
drop.classList.toggle("active");
var dropdownContent = drop.nextElementSibling;
//use classList.toggle with the new class added at the div
dropdownContent.classList.toggle("disp-container");
});
});
nav.side-nav li:not(:first-child):hover {
background: #cda600;
color: white;
cursor: pointer;
}
/*dropdown menu*/
/*remove display here*/
.dropdown-container {
background-color: #ffffff;
padding-left: 8px;
}
/*create a new class and add display here*/
.disp-container {
display: none;
}
<nav class="side-nav">
<ul>
<li style="text-align:left;">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li href="#">some1</li>
<li id="navDrop" class="dropdown-btn">
Menu
</li>
<!-- add your new class here -->
<div class="disp-container dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br />
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br />
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br />
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
<li id="navDrop2" class="dropdown-btn">
Menu
</li>
<!-- add your new class here -->
<div class="disp-container dropdown-container">
<form>
<a class="dropdown-container-link" id="navItem1" href="#">Submenu1</a><br />
<a class="dropdown-container-link" id="navItem2" href="#">Submenu2</a><br />
<a class="dropdown-container-link" id="navItem3" href="#">Submenu3</a><br />
<a class="dropdown-container-link" id="navItem4" href="#">Submenu4</a>
</form>
</div>
</ul>
</nav>
I am having a problem in displaying a iframe on a page.
I have a top frame that displays a logo along the top (which is fine)
I have a menu down the left side of the page. (which I am having a problem with)
I have a frame to the right of the menu that will display my page.
My index.htm page is loading all the frames and looks like this:
<script language="javascript">
function win_resize()
{
var _docHeight = (document.height !== undefined) ? document.height : document.body.offsetHeight;
document.getElementById('leftMenu').height = _docHeight - 90;
}
</script>
<body onresize="win_resize()">
<!-- Header -->
<div id="header">
<div>
<img src="logo.png">
</div>
</div>
<!-- Left Menu -->
<div id="left-sidebar" >
<iframe id="leftMenu" src="menu.htm" STYLE="top:72px; left:0px; position:absolute;" NAME="menu" width="270px" frameborder="0"></iframe>
</div>
<!-- Main Page -->
<div id="content">
<iframe src="users1.htm" STYLE="top:72px" NAME="AccessPage" width="100%" height="100%" frameborder="0"></iframe>
</div>
</body>
My menu.htm page has the following code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en-GB">
<head>
<link rel="stylesheet" type="text/css" href="_styles.css" media="screen">
</head>
<body>
<ol class="tree">
<li>
<li class="file">File 1</li>
<li class="file">File 2</li>
<li class="file">File 3</li>
<li class="file">File 4</li>
<li class="file">File 5</li>
</li>
<li>
<label for="folder2">My Test 1</label> <input type="checkbox" id="folder2" />
<ol>
<li class="file">Settings</li>
<li>
<label for="subfolder2">test1</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
<li>
<label for="subfolder2">test2</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
<li>
<label for="subfolder2">test3</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
</li>
<li>
<label for="folder2">My Test 2</label> <input type="checkbox" id="folder2" />
<ol>
<li class="file">Settings</li>
<li>
<label for="subfolder2">test1</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
<li>
<label for="subfolder2">test2</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
<li>
<label for="subfolder2">test3</label> <input type="checkbox" id="subfolder2" />
<ol>
<li class="file">file1</li>
<li class="file">file2</li>
<li class="file">file3</li>
<li class="file">file4</li>
<li class="file">file5</li>
<li class="file">file6</li>
</ol>
</li>
</li>
</body>
</html>
My _styles.css file has the following:
/* Just some base styles not needed for example to function */
*, html { font-family: Verdana, Arial, Helvetica, sans-serif; }
body, form, ul, li, p, h1, h2, h3, h4, h5
{
margin: 0;
padding: 0;
}
body { background-color: #606061; color: #ffffff; margin: 0; }
img { border: none; }
p
{
font-size: 1em;
margin: 0 0 1em 0;
}
html { font-size: 100%; /* IE hack */ }
body { font-size: 1em; /* Sets base font size to 16px */ }
table { font-size: 100%; /* IE hack */ }
input, select, textarea, th, td { font-size: 1em; }
/* CSS Tree menu styles */
ol.tree
{
padding: 0 0 0 30px;
width: 300px;
}
li
{
position: relative;
margin-left: -15px;
list-style: none;
}
li.file
{
margin-left: -1px !important;
}
li.file a
{
background: url(document.png) 0 0 no-repeat;
color: #fff;
padding-left: 21px;
text-decoration: none;
display: block;
}
li.file a[href *= '.pdf'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href *= '.html'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href $= '.css'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href $= '.js'] { background: url(document.png) 0 0 no-repeat; }
li input
{
position: absolute;
left: 0;
margin-left: 0;
opacity: 0;
z-index: 2;
cursor: pointer;
height: 1em;
width: 1em;
top: 0;
}
li input + ol
{
background: url(toggle-small-expand.png) 40px 0 no-repeat;
margin: -0.938em 0 0 -44px; /* 15px */
height: 1em;
}
li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
li label
{
background: url(folder-horizontal.png) 15px 1px no-repeat;
cursor: pointer;
display: block;
padding-left: 37px;
}
li input:checked + ol
{
background: url(toggle-small.png) 40px 5px no-repeat;
margin: -1.25em 0 0 -44px; /* 20px */
padding: 1.563em 0 0 80px;
height: auto;
}
li input:checked + ol > li { display: block; margin: 0 0 0.125em; /* 2px */}
li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }
The page seems to show correctly except that the menu on the left shows a checkbox where it shouldn't and shold be releaced with the + or - icons.
If I open my menu.htm by it's self it shows correctly
however when I view my index.htm page (which loads the menu in the iframe) it doesn't show the menu correctly as shown below:
however, as soon as I add the following code it shows the menu correctly:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
however, it doesn't show my document height correctly using my win_resize function.
I am guessing that the last bit of code is stopping my document height code from displaying the correct height.
I need that function so it can display my menu frame correctly on the page.
Does anyone know where I have gone wrong, as it works fine by it's self but soon as I call it from a iframe it doesn't display correctly?
An I using the correct code in my function to get the documents height in full or is there a CSS I can use to get the documents height?
Hope you are ready for a long answer :)
There are a bunch of question I have as to why you would approach things the way you are but will take this as constraints for the project you are working on. /cough/ why no jQuery or similar? /cough/
First your iFrame height issue:
I simply changed your code to incorporate a tested cross browser height detection function as follows
<script language="javascript">
function win_resize()
{
var _docHeight = getDocHeight();
document.getElementById('leftMenu').height = _docHeight - 90;
}
//This fixes your calculation of height issue
//Cross browser doc height calculator **Credit to http://james.padolsey.com**
function getDocHeight() {
var D = document;
return Math.max(
Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
Math.max(D.body.clientHeight, D.documentElement.clientHeight)
);
}
</script>
I also added a onload and onresize call to this function so you get initialised at the correct height and also re-sized to the correct height...
<body onload="win_resize()" onresize="win_resize()">
Secondly your pseudo "checked" class will not work in ie8 or below - which I assume you are trying to support as I only got your visible checkbox error in ie.
To remedy this issue I added some basic script to toggle a class name onto the selected input...
<script type="text/javascript">
function getCheckedState(e){
var inputId = e.id;
var getCheckedState = document.getElementById(inputId).checked;
if (getCheckedState == true) {
/*if checked add class*/
e.className += " " + 'checked';
} else {
/*if not checked set class to empty string*/
e.className = "";
}
}
</script>
You will also need to add the .checked class to the relevant styles in your css
e.g.
li input:checked + ol, li input.checked + ol
Thirdly, those pesky visible checkboxes
This was the easy bit, just add opacity and ie opacity filter to your css on the inputs.
li input {
cursor:pointer;
...
opacity: 0;
filter:alpha(opacity=0);
}
Finally - perhaps most importantly
I would seriously question lots about this build and how this nav works. There are surely alternative methods you could use that use native html elements and cross browser tested JS libraries like jQuery to get better compatibility. Not to mention better construction methods over iFrames!
Again that said - I am assuming you are simply constrained here.
One other thing I feel I should point out - is the "onclick" function I use to trigger the change in input state is a deliberate choice again for ie Compatibilty - the "onchange" functionality is supported but doesn't update until loss of onblur of that input leaving it out of sync (for more info onchange checkbox test page)
I hope this answer helps you out even if just one portion of it gets you in the right direction.
Use a reset css file. http://meyerweb.com/eric/tools/css/reset/
Guess it will help you.
The example is very involved, but it looks like it may be this line:
li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
( or another modification to the input's margin values )
Try modifying the margin values of the input and see if it provides the desired results.
My guess is that the iframe is pushing the input value too far to the left when it's added.
Try making all your ids unique , checkbox 2 change two of them and you might be ok because ie is very temperamental. Also label for tags are HTML5 which you should know by now ie hates.