drop - down menu using JS onclick - what is wrong? - javascript

Just learing JS. I have created 3 dropdown menu with different choices and added JS function. HTML and CSS seems to be right. I am concerned about my JS, because it just does not work. Is the even right for that purpose? I am not sure if I use ".this" in the right place.
I would really appreciate any hints!
my JAVASCRIPT:
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM fully loaded and parsed");
var arrow= document.querySelectorAll(".list_arrow");
var panel= document.querySelectorAll(".list_panel");
for (var i= 0; i < arrow.length; i++) {
arrow[i].addEventListener('click', function showDiv(event) {
if (panel.this.style.display == 'none') { //panel(this.style.display=='none')?
panel.this.style.display = 'block';
}
else {
panel.this.style.display = 'none';
}
});
}
});
HERE IS MY CSS
.form {
margin-top:50px;
}
.drop_down_list {
border:1px solid #8de0d2;
width: 280px;
height:38px;
background-color: white;
margin-top:22px;
padding: 8px 12px;
position: relative;
}
.list_label {
font-size: 30px;
color: #e2e2e2;
font-family: 'ralewaylight', Arial, Tahoma, sans-serif;
}
.list_arrow {
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-top: 15px solid #24baa0;
display:block;
position: absolute;
right: 14px;
top: 20px;
cursor: pointer;
}
.list_panel {
background-color: white;
border: 1px solid #ccc;
width: 288px;
padding-left: 15px;
padding-bottom: 10px;
list-style: none;
margin: 0;
left: 0px;
z-index: 2;
position: absolute;
top: 54px;
display:none;
}
.list_panel li {
margin-top:10px;
cursor: pointer;
color: #585858;
}
<div class="form">
<div class="drop_down_list">
<span class="list_label">Choose a chair</span>
<span class="list_arrow"></span>
<ul class="list_panel">
<li>Clair</li>
<li>Margarita</li>
<li>Selena</li>
</ul>
</div>
</div>
<div class="drop_down_list">
<span class="list_label">Choose color</span>
<span class="list_arrow"></span>
<ul class="list_panel">
<li>red</li>
<li>black</li>
<li>orange</li>
</ul>
</div>
<div class="drop_down_list">
<span class="list_label">Choose material</span>
<span class="list_arrow"></span>
<ul class="list_panel">
<li>a</li>
<li>b</li>
</ul>
</div>
</div>

The this keyword refers to the current scope. It is of no use in the state you are using it. What I suggest is to locate the list_panel that is associated with the clicked arrow. There are numerous ways to do that, but you can use the following:
Note that I also added default display-none classes so that they get shown on the first click (this wasn't the case).
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM fully loaded and parsed");
var arrow= document.querySelectorAll(".list_arrow");
for (var i= 0; i < arrow.length; i++) {
arrow[i].addEventListener('click', function showDiv(event) {
// Find the panel associated with the clicked arrow.
var parent = event.target.parentNode,
currentPanel = parent.children[2];
if (currentPanel.style.display == 'none') {
currentPanel.style.display = 'block';
}
else {
currentPanel.style.display = 'none';
}
});
}
});</script>
.form {
margin-top:50px;
}
.drop_down_list {
border:1px solid #8de0d2;
width: 280px;
height:38px;
background-color: white;
margin-top:22px;
padding: 8px 12px;
position: relative;
}
.list_label {
font-size: 30px;
color: #e2e2e2;
font-family: 'ralewaylight', Arial, Tahoma, sans-serif;
}
.list_arrow {
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-top: 15px solid #24baa0;
display:block;
position: absolute;
right: 14px;
top: 20px;
cursor: pointer;
}
.list_panel {
background-color: white;
border: 1px solid #ccc;
width: 288px;
padding-left: 15px;
padding-bottom: 10px;
list-style: none;
margin: 0;
left: 0px;
z-index: 2;
position: absolute;
top: 54px;
display:none;
}
.list_panel li {
margin-top:10px;
cursor: pointer;
color: #585858;
}
<div class="form">
<div class="drop_down_list">
<span class="list_label">Choose a chair</span>
<span class="list_arrow"></span>
<ul class="list_panel" style='display: none'>
<li>Clair</li>
<li>Margarita</li>
<li>Selena</li>
</ul>
</div>
</div>
<div class="drop_down_list">
<span class="list_label">Choose color</span>
<span class="list_arrow"></span>
<ul class="list_panel" style='display: none'>
<li>red</li>
<li>black</li>
<li>orange</li>
</ul>
</div>
<div class="drop_down_list">
<span class="list_label">Choose material</span>
<span class="list_arrow"></span>
<ul class="list_panel" style='display: none'>
<li>a</li>
<li>b</li>
</ul>
</div>
</div>

You may want to try using jQuery to help you with show() and hide() functions, though it is said that you might not need it :P
I don't understand the declaration of panel.. Thus I cannot go along panel.this. My solution is attached here:
http://codepen.io/anon/pen/akXqwA
The main problem is that, during the for-loop, the i will end at the value 3. When the event is triggered, i will always be 3, and I cannot access the panel with panel[i].
So I made a "hack" around it, by getting its nextElementSibling and changing its style.display. Also, I have initialised the value with the HTML (style="display: none;"). If you removed that part, the first click on the arrow will not show the items as the style.display value is not "none". There is a way to avoid changing that in HTML: try playing with the line ;)

Check this:
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM fully loaded and parsed");
var arrow = document.querySelectorAll(".list_arrow");
var panel = document.querySelectorAll(".list_panel");
for (var i = 0; i < arrow.length; i++) {
arrow[i].addEventListener('click', function showDiv(event) {
var ulelm = this.parentNode.querySelector("ul");
if (ulelm.style.display == 'none') {
ulelm.style.display = 'block';
} else {
ulelm.style.display = 'none';
}
});
}
});
working example is here.

Related

How to fix the CSS before/after content and improve the expand/collapse function?

The sidebar menu below works as expected but there are some elements that I would like to fix and improve.
#1 If you expand the 'System Admin' section the line that is displayed on the left side a in the correct place. However, if you
click on the 'Access Control' the line eon the left side is going
below the horizontal line that's pointing to that section. I tried
fixing that with css 'last-child' method but still is not working
correct. If I change percentage from 50% to 85% then the other
section will have an issue.
#2 I'm looking for a better way to expand/collapse the sections. The function show mimic the existing one, but instead of using the object
with key items I would like to use classes instead if possible.
$( document ).ready(function() {
SIDEBAR_OLD.BASE.ExpandCollapse('Auto');
});
const SIDEBAR_OLD = {};
SIDEBAR_OLD.BASE ={};
SIDEBAR_OLD.BASE.ToggleContent = function(section_id) {
let $sContents = $("#section_" + section_id);
if ( $sContents.css("display") != "none" ) {
$sContents.css("display","none");
} else { // Default to seeing the folder's contents:
$sContents.css("display","");
}
};
$("#main-page-wrapper").on("click", ".toggle-menu", function(e){
e.preventDefault();
let section_id = $(this).attr("data-id");
SIDEBAR_OLD.BASE.ToggleContent(section_id);
});
SIDEBAR_OLD.BASE.ExpandCollapse = function(action) {
let $sContents = null,
sExpand = null,
sRoot = false,
items = {1:"m",2:"sysadmin",5:"access"};
for (key in items) {
$sContents = $("#section_" + items[key]);
switch (action) {
case "Expand":
sExpand = "Yes";
break;
case "Collapse":
sExpand = "No";
break;
default:
if ( !(sExpand = $sContents.attr("data-expand")) ) sExpand = "Yes";
}
// Never close root elements automatically. Only ToggleContent(pNumber), below, can do that.
if ( sRoot = $sContents.attr("data-root") ) { // Note! Assignment! "=", not "=="!
if (sRoot == "Yes") sExpand = "Yes";
}
if ( sExpand == "No" ) {
$sContents.css("display","none");
} else { // Default to seeing the folder's contents:
$sContents.css("display","");
}
}
return true;
};
$("#main-page-wrapper").on("click", ".collapse-menu", function(e){
e.preventDefault();
let action = $(this).attr("data-action");
SIDEBAR_OLD.BASE.ExpandCollapse(action);
});
.sidebar {
position: absolute;
top: 56px;
right: 0px;
bottom: 0px;
left: 0px;
width: 180px;
background-color: #0071bc;
color: #fff;
height: calc(100vh - 98px);
overflow: auto;
font-size: 9pt !important;
white-space: nowrap;
}
.sidebar a {
color: #fff;
}
.menuitem {
color: #fff;
font-weight: bold;
text-decoration: none;
}
.menuitem:hover, .menuitem:focus {
color: #ff0;
}
#tree {
font-weight: bold;
padding: 1px;
}
#expandcollapse {
border: 1px solid white;
text-align: center;
}
.sb-row {
border: 0px;
height: 22px;
margin: 0px;
overflow: hidden;
padding: 0px 0px 0px 3px;
position: relative;
white-space: nowrap;
}
.fa-folder-open:before {
color: #DBDB2A !important;
}
.nav>li {
position: relative;
display: block;
}
.nav>li>a {
position: relative;
display: block;
padding: 7px 22px 6px;
}
.nav>li>a:focus {
text-decoration: none;
background: transparent;
background-color: transparent;
}
.nav > li > a:hover {
color: red;
background-color: transparent;
text-decoration: none;
}
.nav.side-menu>li {
position: relative;
display: block;
cursor: pointer;
}
.nav.child_menu li {
padding-left: 20px;
}
.nav.child_menu>li>a {
font-weight: 500;
font-size: 12px;
font-weight: bold;
}
li.first-level::before {
background: #fff;
bottom: auto;
content: "";
height: 1px;
left: 10px;
margin-top: 14px;
position: absolute;
right: auto;
width: 8px;
}
li.first-level::after {
border-left: 1px solid #fff;
bottom: 0;
content: "";
left: 10px;
position: absolute;
top: 0;
}
ul.nav.side-menu li.first-level:last-child::after {
bottom: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<body>
<div class="container body" id="main-page-wrapper">
<div class="sidebar">
<div id="tree" role="navigation" data-expandall="Auto">
<div id="expandcollapse">
<a class="menuitem collapse-menu pr-2" href="#" data-action="Expand">Expand</a> | <a class="menuitem collapse-menu pl-2" href="#" data-action="Collapse">Collapse</a>
</div>
<div class="sb-row">
<a class="toggle-menu" title="Open/Close Folder - System Management" data-id="m">
<i class="fa fa-folder-open fa-lg"></i> System Management
</a>
</div>
<div id="section_m" class="menu-section" data-root="Yes" data-expand="Yes">
<ul class="nav side-menu">
<li class="first-level">
<a class="toggle-menu" href="#" title="System Admin" data-id="sysadmin"><i class="fa fa-folder-open"></i> System Admin</a>
<ul class="nav child_menu first" id="section_sysadmin" data-expand="No">
<li><a class="link-item" data-action="param" title="System Parameters">System Parameters</a></li>
<li><a class="link-item" data-action="schema" title="Select Schema">Select Schema</a></li>
<li><a class="link-item" data-action="item" title="Menu Item">Menu Items</a></li>
</ul>
</li>
<li class="first-level">
<a class="toggle-menu" href="#" title="Access Control" data-id="access"><i class="fa fa-folder-open"></i> Access Control</a>
<ul class="nav child_menu first" id="section_access" data-expand="No">
<li><a class="link-item" data-action="user" title="Manage User">Manage User</a></li>
<li><a class="link-item" data-action="role" title="Manage Role">Manage Role</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
</body>

onClick JS not go to top of the page

I have a page with an initial description, followed by 2 buttons, where the user can choose typeA or typeB. They work by "target": when the user clicks typeA comes the content relative to typeA, bellow the buttons; same to typeB.
typeA is the most common selection, then, when the page loads, a javascript emulates the click to typeA and opens respective content. To avoid hidden the initial description, there is another javascript to put the page at the top. Worked on Chrome and Edge, not on Firefox.
I would like to repeat the same process when the user clicks: opens the respective content, but positioning the page at the top, or, at least, showing the buttons. I thought event onClick calling the same js backToTop would worked - but not.
I put an alert on js and enters there but not execute: always keeps the content of the button selected in its better visibility.
I tried:
window.location.href = '#top';
window.scrollBy(0, -500);
document.html.scrollTop = document.documentElement.scrollTop = 0;
without success.
What am I doing wrong?
<head>
<meta charset="UTF-8">
<title>TOP PAGE TEST</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body,html {margin-left:auto; margin-right:auto;width:70%; font-family:verdana; font-size:1.2em;}
.menuFAQ {background:#aaa; font-size:2em; width:100%;}
.menuFAQ ul {list-style-type:none; position:relative; margin-left:-40px; /* to avoid user agent chrome */}
.menuFAQ li {display:inline-block; margin-top:10px; margin-bottom:10px; width:49%; background:#fff; text-align:center; box-shadow:2px 3px 4px 0px rgba(170,170,170,1); font-weight:400; line-height:80px;}
.menuFAQ li a {display:block; color:#020062; background:#fff; font-weight:400; text-decoration:none;}
.menuFAQ li .active,.menuFAQ li:hover a {color:#fff; font-weight:400; background-image:linear-gradient(#165686, #0f3a5a); }
:target {color:#fff;font-size:1em;}
div.items>div:not(:target) {display:none}
div.items>div:target {display:block; margin-left:auto; margin-right:auto; color:#000; border:1px solid #aaa;}
</style>
</head>
<body>
<div id="top">Top Page</div>
<br>textExp1<br>textExp2<br>textExp3<br>textExp4<br>textExp5
<div class="menuFAQ">
<ul>
<li><a id="preferedFAQ" onclick="backToTop()" class="target" href="#typeA">TypeA</a></li>
<li><a onclick="backToTop()" class="target" href="#typeB">TypeB</a></li>
</ul>
</div>
<div class="items">
<div id="typeA">
<nav>
A long and variable text size to explain TypeA <br>text1A<br>text2A<br>text3A<br>text4A<br>text5A<br>text6A<br>text7A<br>text8A<br>text9A<br>textAA<br>textBA<br>textCA<br>textDA
<br>[...]
</nav>
</div>
</div>
<div class="items">
<div id="typeB">
<nav>
A long and variable text size to explain TypeB
<p>text1B</p><p>text2B</p><p>text3B</p>
<br>[...]
</nav>
</div>
</div>
<script>
const allTargetLinks = document.querySelectorAll('.target')
allTargetLinks.forEach(targetLink => {
targetLink.addEventListener('click', () => {
allTargetLinks.forEach(targetLink => {
targetLink.classList.remove('active')
})
targetLink.classList.add('active')
})
})
window.onload = function() {assignPreferedFAQ()};
function assignPreferedFAQ() {
document.getElementById("preferedFAQ").click();
backToTop();
};
function backToTop() {
//document.html.scrollTop = document.documentElement.scrollTop = 0;
//document.body.scrollTop = document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
};
</script>
You had a real mess there regarding how you process click events and href attribute, i.e:
You had onclick attribute on your links, and you were adding yet another listener to them in JS
You didn't event.preventDefault() in your function, and default browser behavior when you click on a link is to get you to its href path
I've cleaned up a bit and changed some things. Since we need to prevent default behavior :target selector will no longer work, so instead I did what you've already been doing with links, and added an active class to your content. clickHandler() will now remove and add class active as necessary. At the end just scroll to the top. Here's the snippet:
document.querySelectorAll('.target').forEach(targetLink => targetLink.addEventListener('click', clickHandler, false));
function clickHandler(ev) {
ev.preventDefault(); // prevent browser from automatically scrolling to href pos
if (!ev.currentTarget.classList.contains('active')) {
// disable active elements
document.querySelector('.target.active').classList.remove('active');
document.querySelector('.items div.active').classList.remove('active');
// add class to the clicked on button and its corresponding content tab
ev.currentTarget.classList.add('active');
// to prevent pointless string slicing below, you'd have to store ids somewhere else i.e in the data-id attribute
const id = ev.currentTarget.href.slice(ev.currentTarget.href.lastIndexOf('#') + 1);
document.getElementById(id).classList.add('active');
}
window.scrollTo(0,0);
}
* {
font-family: verdana;
font-size: 1em;
}
.menuFAQ {
background: #aaa;
font-size: 2em;
width: 100%;
}
.menuFAQ ul {
list-style-type: none;
text-align: center;
padding: 0;
/* to avoid user agent chrome */
}
.menuFAQ li {
display: inline-block;
width: 48%;
margin-top: 10px;
margin-bottom: 10px;
background: #fff;
text-align: center;
box-shadow: 2px 3px 4px 0px rgba(170, 170, 170, 1);
font-weight: 400;
line-height: 80px;
}
.menuFAQ li a {
display: block;
color: #020062;
background: #fff;
font-weight: 400;
text-decoration: none;
}
.menuFAQ li .active,
.menuFAQ li:hover a {
color: #fff;
font-weight: 400;
background-image: linear-gradient(#165686, #0f3a5a);
}
div.items>div {
display: none;
}
div.items>div.active {
display: block;
margin-left: auto;
margin-right: auto;
color: #000;
border: 1px solid #aaa;
}
<div id="top">Top Page</div>
<br>textExp1<br>textExp2<br>textExp3<br>textExp4<br>textExp5
<div class="menuFAQ">
<ul>
<li><a class="target active" href="#typeA">TypeA</a></li>
<li><a class="target" href="#typeB">TypeB</a></li>
</ul>
</div>
<div class="items">
<div class="active" id="typeA">
<nav>
A long and variable text size to explain TypeA <br>text1A<br>text2A<br>text3A<br>text4A<br>text5A<br>text6A<br>text7A<br>text8A<br>text9A<br>textAA<br>textBA<br>textCA<br>textDA
<br>[...]
</nav>
</div>
</div>
<div class="items">
<div id="typeB">
<nav>
A long and variable text size to explain TypeB
<p>text1B</p>
<p>text2B</p>
<p>text3B</p>
<br>[...]
</nav>
</div>
</div>
Note that instead of artificially clicking at the page load, now your content just loads with class active.
Hope this help you.
< script >
window.onload = function() {
document.getElementById("preferedFAQ").click();
backToTop();
};
function backToTop() {
document.documentElement.scrollTop = document.body.scrollTop = 0;
//alert("enter backToTop");
var elmnt = document.getElementById("top");
var x = elmnt.scrollLeft;
var y = elmnt.scrollTop;
}; <
/script>
body,
html {
margin-left: auto;
margin-right: auto;
width: 70%;
font-family: verdana;
font-size: 1.2em;
}
.menuFAQ {
background: #aaa;
font-size: 2em;
width: 100%;
}
.menuFAQ ul {
list-style-type: none;
position: relative;
margin-left: -40px;
/* to avoid user agent chrome */
}
.menuFAQ li {
display: inline-block;
margin-top: 10px;
margin-bottom: 10px;
width: 49%;
background: #fff;
text-align: center;
box-shadow: 2px 3px 4px 0px rgba(170, 170, 170, 1);
font-weight: 400;
line-height: 80px;
}
.menuFAQ li a {
display: block;
color: #020062;
background: #fff;
font-weight: 400;
text-decoration: none;
}
.menuFAQ li .active,
.menuFAQ li:hover a {
color: #fff;
font-weight: 400;
background-image: linear-gradient(#165686, #0f3a5a);
}
:target {
color: #fff;
font-size: 1em;
}
div.items>div:not(:target) {
display: none
}
div.items>div:target {
display: block;
margin-left: auto;
margin-right: auto;
color: #000;
border: 1px solid #aaa;
}
<div id="top">Top Page</div> <br>textExp1<br>textExp2<br>textExp3<br>textExp4<br>textExp5<br>textExp6<br>textExp7<br>textExp8<br>textExp9<br>textExpA<br>textExpB<br>textExpC<br>textExpD
<br>textExpE
<div class="menuFAQ">
<ul>
<li><a id="preferedFAQ" onclick="backToTop()" class="target" href="#typeA">TypeA</a></li>
<li><a onclick="backToTop()" class="target" href="#typeB">TypeB</a></li>
</ul>
</div>
<div class="items">
<div id="typeA">
<nav>
A long and variable text size to explain TypeA <br>text1A<br>text2A<br>text3A<br>text4A<br>text5A<br>text6A<br>text7A<br>text8A<br>text9A<br>textAA<br>textBA<br>textCA<br>textDA
<br>[...]
</nav>
</div>
</div>
<div class="items">
<div id="typeB">
<nav>
A long and variable text size to explain TypeB
<p>text1B</p>
<p>text2B</p>
<p>text3B</p>
<br>[...]
</nav>
</div>
</di

Menu not showing up after using document click function event

I am currently creating multiple navigation buttons for my website, each of them would show up menus.
So as example, this is the first menu:
<div class="outer-bar">
<ul class="down-bar" style="list-style:hidden">
<li>
<label id="down-nav-1" class="down-nav" onclick="Dropdown1()">Knives <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-1">
<label class="m9_bayonet" style="width:30px;height:30px;position:absolute;top:5px;left:5px;cursor:pointer;"></label>M9 Bayonet
<label class="karambit" style="width:30px;height:30px;position:absolute;left:5px;top:59px;cursor:pointer;"></label>Karambit
<label class="bayonet" style="width:30px;height:30px;position:absolute;left:5px;top:116px;cursor:pointer;"></label>Bayonet
<label class="butterfly" style="width:30px;height:30px;position:absolute;left:5px;top:170px;cursor:pointer;"></label>Butterfly Knife
<label class="flip" style="width:30px;height:30px;position:absolute;left:5px;top:225px;cursor:pointer;"></label>Flip Knife
<label class="falchion" style="width:30px;height:30px;position:absolute;left:5px;top:280px;cursor:pointer;"></label>Falchion Knife
<label class="gut" style="width:30px;height:30px;position:absolute;left:5px;top:334.5px;cursor:pointer;"></label>Gut Knife
<label class="shadow" style="width:30px;height:30px;position:absolute;left:5px;top:390px;cursor:pointer;"></label>Shadow Daggers
<label class="huntsman" style="width:30px;height:30px;position:absolute;left:5px;top:444px;cursor:pointer;"></label>Huntsman Knife
<label class="bowie" style="width:30px;height:30px;position:absolute;left:5px;top:498.5px;cursor:pointer;"></label>Bowie Knife
</div>
</div>
</li>
So as you see on the <label> element #down-nav-1, it has onclick attribute linked to the function Dropdown1() and Display of menu is None and the time.
And this is the function itself in Javascript:
function Dropdown1() {
document.getElementById("dropdown-menu-1").style.display = "inline-block";
document.getElementById("down-nav-1").style.cssText = "border: solid 3px gray;background-color: gray;border-radius: 10px;";
}
All of this would simply work fine, please see Fiddle. (Only "Knives" button works atm).
But then i tried to add a function, so when user clicks outside of the menu, the display would be set to 'None' again:
function Dropdown1() {
document.getElementById("dropdown-menu-1").style.display = "inline-block";
document.getElementById("down-nav-1").style.cssText = "border: solid 3px gray;background-color: gray;border-radius: 10px;";
}
$(document).click(function(event) {
if(!$(event.target).closest('#dropdown-menu-1').length) {
if ( ($('#dropdown-menu-1').style.display = "None" ) {
$('#dropdown-menu-1').style.display = "inline-block";
}
}
})
And after adding this code, there would be no action when clicking the button. ( see the result ).
I don't understand the specific problem in there, but please note, i am new to Javascript, and don't know many things in there.
What could the problem be? can i do this with pure Javascript or should i use jquery in this case?
There is syntax & logical error in the code.
Updated your code:
function Dropdown1() {
if ($('#dropdown-menu-1').css("display") !== "none") {
$('#dropdown-menu-1').css("display", "none");
} else {
$('#dropdown-menu-1').css("display", "inline-block");
}
document.getElementById("down-nav-1").style.cssText = "border: solid 3px gray; background-color: gray; border-radius: 10px;";
}
$(document).click(function(event) {
if (!$(event.target).closest('.outer-bar').length) {
if ($('#dropdown-menu-1').css("display") !== "none") {
$('#dropdown-menu-1').css("display", "none");
}
}
});
Please use == or === instead of the = operator when comparing inside your if blocks.
Also brackets were not closed in the if block expressions.
Also, style.display is a property associated to a JavaScript object and not a jQuery object. You should use .css("display") for a jQuery object.
Updated working fiddle: https://jsfiddle.net/nashcheez/bjfz7twq/7/
If you are using jQuery, please use it consistently. Don't mix both jQuery and Vanilla JavaScript. To do something very simple dropdown like that, you just need to use JavaScript to only change classes and not the original effect. All the others should be handled by CSS.
Technically, this is achievable just using HTML and CSS. There are 1000s of examples outside. Also, you should use event handlers instead of functions for individual dropdowns, as it is better for scalability.
First thing, change this in CSS:
.mainsizer.open .dropdown-menus {
display: block;
}
And in your JavaScript, do this:
$(function () {
$("label").click(function () {
if ($(this).next(".mainsizer").hasClass("open"))
$(this).next(".mainsizer").toggleClass("open");
else {
$(".open").removeClass("open");
$(this).next(".mainsizer").addClass("open");
}
});
});
Ultimately, you should have this code:
$(function () {
$("label").click(function () {
if ($(this).next(".mainsizer").hasClass("open"))
$(this).next(".mainsizer").toggleClass("open");
else {
$(".open").removeClass("open");
$(this).next(".mainsizer").addClass("open");
}
});
});
.outer-bar {
position: relative;
display: block;
z-index: 1;
text-align: center;
top: 55px;
background-color: black;
height: 60px;
width: 100%;
}
.down-bar {
list-style-type: none;
font-size: 105%;
}
.down-bar li {
display: inline-block;
margin-top: 15px;
margin-right: 2%;
vertical-align: top;
}
.down-nav {
z-index: 1
font-size: 105%;
color: white;
font-family: 'Lato';
cursor: pointer;
transition: all 0.1s ease;
-moz-transition: all 0.1s ease;
}
.down-nav:hover {
color: white;
border: solid 3px gray;
background-color: gray;
border-radius: 10px;
font-family: 'Lato';
}
.down-nav li {
display: inline-block;
}
.caret_down {
font-size: 30%;
}
.mainsizer {
position: absolute;
width: 164px;
}
.dropdown-menus {
display: none;
position: absolute;
width: 164px;
right: 5%;
background-color: black;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 99;
transition: 0.1s ease-in;
margin-top: 5px;
}
.dropdown-menus a {
color: white;
text-align: center;
font-size: 0.9em;
padding: 8% 0px 15% 0%;
padding-right: 10%;
text-decoration: none;
display: block;
list-style-type: none;
white-space: nowrap;
margin-left: 0%;
text-indent: 4%;
font-family: 'Lato';
}
.dropdown-menus a:hover {
background-color: gray;
}
.mainsizer.open .dropdown-menus {
display: block;
}
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<div class="outer-bar">
<ul class="down-bar" style="list-style:hidden">
<li>
<label id="down-nav-1" class="down-nav" onclick="Dropdown1()">Knives <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-1">
<label class="m9_bayonet" style="width:30px;height:30px;position:absolute;top:5px;left:5px;cursor:pointer;"></label>M9 Bayonet
<label class="karambit" style="width:30px;height:30px;position:absolute;left:5px;top:59px;cursor:pointer;"></label>Karambit
<label class="bayonet" style="width:30px;height:30px;position:absolute;left:5px;top:116px;cursor:pointer;"></label>Bayonet
<label class="butterfly" style="width:30px;height:30px;position:absolute;left:5px;top:170px;cursor:pointer;"></label>Butterfly Knife
<label class="flip" style="width:30px;height:30px;position:absolute;left:5px;top:225px;cursor:pointer;"></label>Flip Knife
<label class="falchion" style="width:30px;height:30px;position:absolute;left:5px;top:280px;cursor:pointer;"></label>Falchion Knife
<label class="gut" style="width:30px;height:30px;position:absolute;left:5px;top:334.5px;cursor:pointer;"></label>Gut Knife
<label class="shadow" style="width:30px;height:30px;position:absolute;left:5px;top:390px;cursor:pointer;"></label>Shadow Daggers
<label class="huntsman" style="width:30px;height:30px;position:absolute;left:5px;top:444px;cursor:pointer;"></label>Huntsman Knife
<label class="bowie" style="width:30px;height:30px;position:absolute;left:5px;top:498.5px;cursor:pointer;"></label>Bowie Knife
</div>
</div>
</li>
<li>
<label id="down-nav-2" class="down-nav">Pistols <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-2">
</label>Glock-18
</label>USP-S
</label>P2000
</label>Five-SeveN
</label>Desert Eagle
</label>Tec-9
</label>CZ75-Auto
</label>P250
</label>Dual Berettas
</label>R8 Revolver
</div>
</div>
</li>
<li>
<label id="down-nav-4" class="down-nav">SMGs <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-3">
</label>P90
</label>MAC-10
</label>MP7
</label>MP9
</label>PP-Bizon
</label>UMP-45
</div>
</div>
</li>
<li>
<label id="down-nav-5" class="down-nav">Rifles <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-4">
</label>AK-47
</label>Galil AR
</label>SG 553
</label>M4A4
</label>M4A1-S
</label>AUG
</label>Famas
</div>
</div>
</li>
<li>
<label id="down-nav-6" class="down-nav">Snipers <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-5">
</label>AWP
</label>SSG 08
</label>SCAR-20
</label>G3SG1
</div>
</div>
</li>
<li>
<label id="down-nav-6" class="down-nav">Heavy <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-6">
</label>Nova
</label>MAG-7
</label>XM1014
</label>Sawed-Off
</label>Negev
</label>M249
</div>
</div>
</li>
<li>
<label id="down-nav-7" class="down-nav">Others <b class="caret_down">▼</b></label>
<div class="mainsizer">
<div class="dropdown-menus" id="dropdown-menu-7">
</label>Keys
</label>Cases
</label>Passes
</label>Capsules
</label>Pins
</label>Packages
</label>Stickers
</label>Music Kits
</div>
</div>
</li>
</ul>
</div>
Full Screen Output: http://output.jsbin.com/jeropupogu
Here's a minimal, working (although not styled completely) version, using no JS, and very basic HTML and CSS. Should work in any browser.
.nav {
display: block;
background-color: black;
height: 5em;
}
.nav a {
color: white;
}
.nav ul {
list-style-type: none;
}
.nav > ul > li {
display: inline-block;
}
.nav ul li > ul {
display: none;
}
.nav ul li:hover > ul {
display: block;
}
.down-nav {
font-size: 105%;
color: white;
font-family: 'Lato';
cursor: pointer;
transition: all 0.1s ease;
border: solid .2em transparent;
}
.down-nav:hover {
border: solid .2em gray;
background-color: gray;
border-radius: 1em;
font-family: 'Lato';
}
<div class="nav">
<ul>
<li class="down-nav">Knives <span>▼</span>
<ul>
<li>M9 Bayonet</li>
<li>Karambit</li>
<li>Bayonet</li>
<li>Butterfly Knife</li>
<li>Flip Knife</li>
<li>Falchion Knife</li>
<li>Gut Knife</li>
<li>Shadow Daggers</li>
<li>Huntsman Knife</li>
<li>Bowie Knife</li>
</ul>
</li>
<li class="down-nav">Pistols <span>▼</span>
<ul>
<li>Glock-18</li>
<li>USP-S</li>
<li>P2000</li>
<li>Five-SeveN</li>
<li>Desert Eagle</li>
<li>Tec-9</li>
<li>CZ75-Auto</li>
<li>P250</li>
<li>Dual Berettas</li>
<li>R8 Revolver</li>
</ul>
</li>
</ul>
</div>

Looking for ways to refactor my jQuery code for a div toggle I created

I wrote some code with three things in mind:
Highlighting a selection's border using 'on click'.
Selecting one item will remove the highlight from the other item.
The ability to deselect each item on click.
I've managed to get everything working for the most part, but I don't particularly like how complex the code is for the radial dot that appears when one item is selected.
Below is an example of what I'm talking about, particularly I'm looking for ways to refactor the code below into something a little more legible (shorter).
$(this).children('.radial').children().toggleClass('checked').parents('.itembox')
.siblings().children('.radial').children().removeClass('checked');
Here's a working example for more context (line 10):
var raceInternet = false;
var racePhone = false;
var raceTv = false;
$(function() {
var $targetDiv = $('#race-internet > .itembox');
var $radialDot = $('.radial > .center-dot');
$targetDiv.on('click', function() {
$(this).toggleClass('user-selected').siblings().removeClass('user-selected');
//Is it possible to refactor Line 10?
$(this).children('.radial').children().toggleClass('checked').parents('.itembox').siblings().children('.radial').children().removeClass('checked');
if ($targetDiv.is('.user-selected')) {
raceInternet = true;
} else {
raceInternet = false;
}
})
})
.itembox-container {
display: flex;
}
.boxes-2 {
width: calc((100% - 25px)/2);
margin: 10px;
padding: 10px;
}
.itembox {
position: relative;
display: inline-block;
border: 5px solid #e8e8e8;
border-radius: 10px;
cursor: pointer;
}
.user-selected {
border: 5px solid #E16E5B;
}
.itembox h4 {
color: #22ddc0;
font-weight: 700;
}
span.price {
display: inline-block;
font-weight: 400;
float: right;
color: #22ddc0;
}
.itembox > ul {
list-style: none;
}
.itembox > ul > li {
line-height: 3;
}
.radial {
position: absolute;
float: right;
height: 35px;
width: 35px;
padding: 2px;
border: 5px solid #e8e8e8;
border-radius: 50%;
top: 43%;
right: 10px;
}
.center-dot {
display: none;
position: relative;
height: 21px;
width: 21px;
background-color: #E16E5B;
border-radius: 50%;
}
.checked {
display: block;
}
.prime-aux:first-of-type {
top: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">
<!-- Primary Content Container -->
<div class="prime-aux">
<div id="race-internet" class="itembox-container">
<div class="itembox boxes-2">
<h4>Gigabit Internet <span class="price">$60/mo</span></h4>
<ul>
<li>1,000 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
<div class="itembox boxes-2">
<h4>Basic Internet <span class="price">$25/mo</span></h4>
<ul>
<li>25 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
</div>
</div>
</section>
<!-- Primary Content Container End -->
View on JS Fiddle
You can eliminate a lot of your jQuery by just leveraging CSS. Typically, if I want to toggle a feature, I have it either display: block; or display: none; based upon a CSS selector. Then, I just use jQuery to toggle the parent element's class name. So for example:
.item.selected .checkmark {
display: block;
}
.item .checkmark {
display: none;
}
$('.item').click(function(){ $(this).toggleClass('selected') });
JSFiddle

Show span if parent div hasClass()

I'm beating myself over the head with this one. I don't know what's doing on. It's pretty simple but it just doesn't work. I want to show a span item when a div has a class. Yup, basic, but I can't get it to work.
Here is my HTML with the class add-product
<div id="ot-pr" class="status-publish has-post-thumbnail hentry add-product">
<span class="arrow">Testing</span>
</div>
And this is the JavaScript
$(document).ready(function($){
if ($("#ot-pr").hasClass('add-product')){
$(".arrow").show();
} else {
$(".arrow").hide();
}
});
Here is the CSS of the .arrow
.arrow {
display: none;
width: 0; height: 0;
line-height: 0;
border-right: 16px solid transparent;
border-top: 10px solid #c8c8c8;
top: 60px;
right: 0;
position: absolute;
}
What have I tried, adding a find(span) and add else if:
$(document).ready(function(){
if ($("#ot-pr").hasClass('add-product')){
$(".arrow").find('span').show();
} else if {
$(".arrow").hide();
}
});
Both separate or together don't work. Why isn't this working. This should be basic right?! I get no console errors and jQuery.js as been added to the page. All other scripts work just fine.
There's no need for JS here, you can achieve this in CSS alone:
.arrow {
display: none;
/* simplified CSS for the example */
}
div.add-product .arrow {
display: block;
}
<div id="ot-pr" class="status-publish has-post-thumbnail hentry add-product">
<span class="arrow">arrow 1</span>
</div>
<div id="ot-pr" class="status-publish has-post-thumbnail hentry add-product">
<span class="arrow">arrow 2</span>
</div>
<!-- not visible -->
<div id="ot-pr" class="status-publish has-post-thumbnail hentry">
<span class="arrow">arrow 3</span>
</div>
I think no need to write javascript for this, you can manage it by CSS code only
.arrow {
display: none;
width: 0; height: 0;
line-height: 0;
border-right: 16px solid transparent;
border-top: 10px solid #c8c8c8;
top: 60px;
right: 0;
position: absolute;
}
div.add-product > span.arrow
{
display: block !important;
}
$(document).ready(function(){
if($("#ot-pr").hasClass('add-product') == true){
$(".arrow").css("display","block");
}
else {
$(".arrow").css("display","none");
}
});
jQuery solution:
var $arrow = $('.arrow'),
$otPr = $('#ot-pr');
$otPr.hasClass('add-product')
? $arrow.show()
: $arrow.hide();
.arrow {
display: block;
/* ... */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="ot-pr" class="status-publish has-post-thumbnail hentry add-product">
<span class="arrow">Some text</span>
</div>
replace css with
.arrow {
display: block;
width: 100px; height: 100px;
line-height: 0;
border-right: 16px solid transparent;
border-top: 10px solid #c8c8c8;
top: 60px;
right: 0;
position: absolute;
}
just add display:block and add height width

Categories