simplifying a javascript click count menu controlling 3 individual dropdowns - javascript

I've got 3 individual slide down menu's at the top of my page.
Page Menu
Account dropdown
Cart Dropdown
I've created individual open and close functions for each one
function menu_open(){
document.getElementById("myNav_overlay").style.height = "100%";
document.getElementById("myNav").style.height = "100%";
$('.menu-link').text("menu_open");
}
function menu_close() {
document.getElementById("myNav_overlay").style.height = "0%";
document.getElementById("myNav").style.height = "0%";
$('.menu-link').text("menu");
}
function account_open(){
document.getElementById("myAccount_overlay").style.height = "100%";
document.getElementById("myAccount").style.height = "100%";
$('.account-link').text("person");
}
function account_close() {
document.getElementById("myAccount_overlay").style.height = "0%";
document.getElementById("myAccount").style.height = "0%";
$('.account-link').text("person");
}
function cart_open(){
document.getElementById("myCart_overlay").style.height = "100%";
document.getElementById("myCart").style.height = "100%";
$('.cart-link').text("shopping_cart");
}
function cart_close() {
document.getElementById("myCart_overlay").style.height = "0%";
document.getElementById("myCart").style.height = "0%";
$('.cart-link').text("shopping_cart");
}
and then 3 individual click count functions to determine if the menu needs to open or close.
$(function() {
var menuclickCount = 0;
var accountclickCount = 0;
var cartclickCount = 0;
$('.menu-link').click(function () {
if(menuclickCount%2==0){
//do when open
menu_open();
account_close();
cart_close();
}else{
//do when closed
menu_close();
}
clickCount++;
});
$('.account-link').click(function () {
if(accountclickCount%2==0){
//do when open
account_open();
menu_close();
cart_close();
}else{
//do when closed
account_close();
}
accountclickCount++;
});
$('.cart-link').click(function () {
if(cartclickCount%2==0){
//do when open
cart_open();
menu_close();
account_close();
}else{
//do when closed
cart_close();
}
cartclickCount++;
});
});
This seems rather large compared to what it has to be and seems like there may be a better/simpler way of doing it. But honestly not sure how this would typically be done.
Is it better to leave a setup like this as is where each one is controlled individually and manually closes the other? OR, is it better to combine these into a more robust, smaller function that still controls them as needed?
If it is better to combine into a simpler function, how would this be done to where it still opens and closes each dropdown section?
I took 1 working function and duplicated it to make this work as is. So now I'm curious to see how this compares to what is considered industry standard and practical.
The HTML is simple....
Menu content
<div id="myNav_overlay" class="overlay_background"></div>
<div id="myNav" class="nav-overlay">
<div class="overlay-content">
MENU
</div>
</div>
Account content
<div id="myAccount_overlay" class="overlay_background"></div>
<div id="myAccount" class="account-overlay">
<div class="overlay-content">
ACCOUNT
</div>
</div>
Cart content
<div id="myCart_overlay" class="overlay_background"></div>
<div id="myCart" class="cart-overlay">
<div class="overlay-content">
CART
</div>
</div>

Without getting into styling the example too much, using the wonder of jQuery, you can do this:
(1) On click, select all menu containers (class .ddown in my example)
(2) return all menu containers to their default height of zero (by removing the .showMenu class with its new height)
(3) for the clicked container only, apply a style that increases container height.
$('.ddown').click(function(){
$('.ddown').removeClass('showMenu');
$(this).addClass('showMenu');
});
.container{height:100px;}
.ddown{display:inline-block;width:100px;border:1px solid #ccc;overflow:hidden;}
.mnuTitle{height:20px;}
.mnuContent{height:0;background:white;}
.showMenu{height:100px;background:palegreen;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="container">
<div id="myNav" class="ddown">
<div class="mnuTitle">Menu</div>
<div class="mnuContent">
MENU CONTENT
</div>
</div>
<div id="myAccount" class="ddown">
<div class="mnuTitle">Account</div>
<div class="mnuContent">
ACCOUNT CONTENT
</div>
</div>
<div id="myCart" class="ddown">
<div class="mnuTitle">Cart</div>
<div class="mnuContent">
CART CONTENT
</div>
</div>
</div><!-- .container -->

Related

Toggle re-hides all divs; need parent div to remain visible

Apologies in advance, I'm not terribly familiar with Javascript, but I do understand what this code is doing and why it is causing me this problem. I'm just not sure how to go about solving it AT all.
On my webpage I have an open/close dialogue toggle which is the parent div, the dialogue box is hidden upon the page loading. Within this dialogue box are more hidden divs for the dialogue options. Problem is, when one of the dialogue options is clicked, the script hides the entire dialogue box, preventing any of the dialogue options from being seen, because it can only show one div at a time, regardless of its parent or child status. When a div is clicked, all other divs are re-hidden.
I need the parent div to remain visible until the dialogue box toggle is clicked again. The individual choices DO need to hide/unhide when another choice is clicked.
Not sure if I should include any CSS here, it's just styling the dialogue box and its buttons within.
<div id="dialogue" style="display:none;">
<div class="room">
Room description here. What do you do?
<div class="buttons">
Pet the cat.
<br>
<div id="cat" style="display:none;">aw yeah kitty time</div>
Turn on the radio.
<br>
<div id="radio" style="display:none;">
<br>
audio file and tracklist here
</div>
</div>
</div>
</div>
<span class="toggle">
[Open/close dialogue.]
</span>
<script type="text/javascript">
var divs = ["cat", "radio", "dialogue"];
var visibleDivId = null;
function divVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
I probably need a third function here because currently all the toggles are grouped together, hence why they're interacting like this, but I don't have the first clue how to accomplish this. I have been looking and haven't found anything that seems to match my needs.
Made a few corrections to your HTML so the href does not refresh the page on click. Also added in a few attributes (aria-controls) to track which div the button controls. I added comments to the JavaScript. There are plenty of Aria attributes they typically help with accessibility but they are super useful for keeping track of things in HTML and passing information to JavaScript.
//create a function to handle the click that takes in the event as a argument
function handleClick(event) {
//find out which div the button controls
const ariaControls = event.currentTarget.getAttribute("aria-controls"),
//select the controlled div
controlledAria = document.getElementById(ariaControls);
// if the controlled div is cat
if (ariaControls === "cat") {
// hide the radio div
document.getElementById("radio").classList.add("hide");
// if the controlled div is radio
} else if (ariaControls === "radio") {
// hide the car div
document.getElementById("cat").classList.add("hide");
}
//toggle the hide div on the controlled div
controlledAria.classList.toggle("hide");
}
//select all the buttons
const buttons = document.querySelectorAll("button");
//for each button add an event listener when the button is clicked run the handle click function
buttons.forEach(button => button.addEventListener("click", handleClick))
.hide {
display: none;
}
<div id="dialogue" class="hide">
<div class="room">
Room description here. What do you do?
<div class="buttons">
<button aria-controls="cat">Pet the cat.</button><br>
<div id="cat" class="hide">aw yeah kitty time</div>
<button aria-controls="radio">Turn on the radio.</button><br>
<div id="radio" class="hide">audio file and tracklist here
</div>
</div>
</div>
</div>
<span class="toggle"><button aria-controls="dialogue">[Open/close dialogue.]</button></span>

Why does my onclick hamburger button stop working after event?

I'm new to coding and have no idea what I'm doing. But I managed to make something cool, but I can't repeat the coolness.
I'm working on my mobile design, and I made it where you click the burger, sidenav opens, and when you click to the right of the sidebar, the sidebar closes. Very cool.
The problem is that now it seems my onclick hamburger button is unclickable after it runs the event. Please help me. What am I doing wrong? How can I make my hamburger have unlimited functional click events? Thanks.
See my JS FIDDLE:
http://jsfiddle.net/r214g0oc/1/
HTML:
<header id="navbar">
<div >
<img src="img/Logo.jpg" alt="logo" class="hmainlogo"/>
<button class="openbtn" onclick="openNav()">☰</button>
</div>
<div id="main">
<div id="mySidebar" class="sidebar">
<img src="img/Logo.jpg" alt="logo" class="hsblogo"/>
<ul>
<li>Home</li>
<li>About</li>
<li>Services</li>
<li>Rates</li>
<li>Reviews</li>
</ul>
Free Consult
</div>
</div>
</header>
JAVASCRIPT:
function openNav() {
document.getElementById("mySidebar").style.width = "150px";
document.getElementById("main").style.marginLeft = "150px";
}
function handleMousePos(event) {
var mouseClickWidth = event.clientX;
if (mouseClickWidth >= 150) {
document.getElementById("mySidebar").style.left = '-150px';
}
}
document.addEventListener("click", handleMousePos);
The code works every time, but it's just doing what you tell it (the bane of all computer programming).
You're saying that if the user clicks in a place right of the 150px mark, it should move the sidebar to -150px (offscreen). Clicking again... moves the sidebar to -150px: in other words, it doesn't move it.
If what you're after is a toggle, you need to check to see where the sidebar is now, and if it's already offscreen, move it back onscreen.
if (document.getElementById("mySidebar").style.left == '-150px') document.getElementById("mySidebar").style.left =0;
This is pretty clunky coding style, though/ Better would be to use CSS, and define two styles: one for the sidebar in place and one without, and then check for which style is applied, and toggle the styles with addStyle and removeStyle.
Ciao, your problem is on handleMousePos. If mouseClickWidth >= 150 then you assign -150px to mySidebar style. Ok but you forgot the else statement to reassign 0px to your mySidebar.
So your code becomes:
function handleMousePos(event) {
var mouseClickWidth = event.clientX;
if (mouseClickWidth >= 150) {
document.getElementById("mySidebar").style.left = '-150px';
}
else {
document.getElementById("mySidebar").style.left = '0px';
}
}
Here your code modified.
Your handleMousePos(event) could be the problematic function here. You aren't removing the -150px after it gets added. So my best suggestion would be to modify it this way:
function openNav() {
document.getElementById("mySidebar").style.left = '0px';
document.getElementById("mySidebar").style.width = "150px";
document.getElementById("main").style.marginLeft = "150px";
}
The better method would still be to use CSS for it and adding and removing a particular attribute like a class name which has its style already defined.
Or you may opt to use a hidden checkbox and have your hamburger menu be a label for it. That will make it easier on the CSS side as you can just add :checked and define your expanded sidebar properties

How to undo "this.onclick=null"? How to restore javascript onclick functionality to a div?

I am displaying a div with a default background color. When I click it once, it changes color. A second click does nothing, because the div has this code: "this.onclick=null". That much works well.
However, after I click the div once, I want to click a button to restore its onclick functionality. But the button I have created for that purpose doesn't work, because I don't know what javascript code to use. Does anyone know?
As you can see, I'm working with Bootstrap 3. (Please note that I am a beginner with only basic knowledge of php and js.) Here is my code:
HTML for the div:
<div class="row">
<div class="col-sm-12">
<div id="testDiv" style="background-color: #0000FF" onclick="colorClick(id); this.onclick=null;">
Clicking this div once changes the color.
</div>
</div>
</div>
JAVASCRIPT for the div:
function colorClick(id){
var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);  
document.getElementById(id).style.backgroundColor=randomColor;
/* The random color generator is from stackoverflow.com/questions/1484506/random-color-generator */
}
HTML for the button:
<div class="row">
<div class="col-sm-12">
    <button type='button' class='btn btn-default btn-lg' onclick=reEnableOnclick()>
This button should re-enable the onclick functionality, but it does not
</button>
</div>
</div>
JAVASCRIPT for the button:
function reEnableOnclick(){
document.getElementById("testDiv").onclick=click;  /* This is only pseudo-code. What real code should I put here? */
}
(Both js functions are in a separate .js document)
EDIT #2: This needs to work for about 100 divs on the same page.
Since you need to apply this functionality to 100s of divs, try keeping track of just the locked states rather than all the divs states at all times. Assuming each div id is unique you could try:
Javascript:
let locked = [];
function lockCheckRun(id) {
let divID = document.getElementById(id);
if (!locked.includes(divID) {
colorClick(id);
locked.push(divID);
}
}
function lockReset() {
locked.length = 0;
}
Explanation:
create an empty array to store locked element ids. We'll call this array 'locked'.
next, create a function which checks to see if the locked array includes the current unique element id. if it does not, then we will run your 'colorClick' function. once that completes, we will add the current element id to the 'locked' array via .push()
when you want to reset your locked element array, run the 'lockReset' function.
Optional Polyfill for comptability with older browsers:
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
'use strict';
if (search instanceof RegExp) {
throw TypeError('first argument must not be a RegExp');
}
if (start === undefined) { start = 0; }
return this.indexOf(search, start) !== -1;
};
}
Assign the original onclick code.
function reEnableOnclick() {
document.getElementById("testDiv").onclick = "colorClick(id); this.onclick=null;";
}
You can have a pseudo variable inside your javascript code that serves the purpose
In this case you can write
HTML Code
<div class="row">
<div class="col-sm-12">
<div id="testDiv" style="background-color: #0000FF" onclick="colorClick(id)">
Clicking this div once changes the color.
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<button type='button' class='btn btn-default btn-lg' onclick=reEnableOnclick()>
This button should re-enable the onclick functionality, but it does not
</button>
</div>
</div>
Javascript Code
var divDisabled = false;
function colorClick(id){
if(!divDisabled) {
var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
document.getElementById(id).style.backgroundColor=randomColor;
divDisabled = true;
/* The random color generator is from stackoverflow.com/questions/1484506/random-
color-generator */
}
}
function reEnableOnclick(){
divDisabled = false;
}
So now, You will set divDisabled for false by default so the first click of div will work as you want & following clicks on div won't as it is currently,
But As soon as you hit the button click it enables the click on div with setting buttonDisable to false, so it will again work once on div, as you want
Don't remove the click event, just check a flag to see if the behaviour is enabled or not. E.G:
var clickEnabled = true;
function colorClick(id) {
if (clickEnabled) {
var randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
document.getElementById(id).style.backgroundColor = randomColor;
clickEnabled = false;
}
}
function reEnableOnclick() {
clickEnabled = true;
}
<div class="row">
<div class="col-sm-12">
<div id="testDiv" style="background-color: #0000FF" onclick="colorClick(id);">
Clicking this div once changes the color.
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<button type='button' class='btn btn-default btn-lg' onclick=reEnableOnclick()>
This button will re-enable the onclick functionality
</button>
</div>
</div>
You could define the function to run onclick outside of the assignment and use it to set and reset the click handler...
function functionThatRunsWhenButtonClicked() {
// do stuff
}
then in the places you need to assign it, assign it..
<div class="row">
<div class="col-sm-12">
<div id="testDiv" style="background-color: #0000FF" onclick="functionThatRunsWhenButtonClicked(); this.onclick=null;">
Clicking this div once changes the color.
</div>
</div>
</div>
function reEnableOnclick(){
document.getElementById("testDiv").onclick=functionThatRunsWhenButtonClicked; /* This
is only pseudo-code. What real code should I put here? */
}
You can do the same thing with colorClick(id)

Multiple uses of the same script causing functionality errors

Sorry for the lack of knowledge but I don't know where else to turn. I had been working on the CSS for a project while the javascript was handled by a colleague. That colleague has now left the company and I have to finish his work to hit a deadline with very little knowledge of javascript. He had created a simple function (show/hide) that allowed us to show and hide content with an unordered list. Namely when you click on a list item, the corresponding div shows and the rest hides.
This was working fine, however I have since been asked to duplicate this so that multiple (show/hides) can be used on the page. When I did this the first one works ok, but the next scripts intefere with eachother and also hide content in the other divs. I've tried to fix this using my non-existent knowledge of javascript but to know avail (attempt is below). Any help here would be massively appreciated. Thanks in advance!
function toggle(target) {
var artz = document.getElementsByClassName('history');
var targ = document.getElementById(target);
var isVis = targ.style.display == 'block';
// hide all
for (var i = 0; i < artz.length; i++) {
artz[i].style.display = 'none';
}
// toggle current
targ.style.display = isVis? 'none' : 'block';
return false;
}
function toggle2(target) {
var artz2 = document.getElementsByClassName('vision');
var targ2 = document.getElementById(target2);
var isVis2 = targ.style.display == 'block';
// hide all
for (var i = 0; i < artz2.length; i++) {
artz2[i].style.display = 'none';
}
// toggle current
targ2.style.display = isVis2? 'none' : 'block';
return false;
}
jQuery(document).ready(function($) {
$('.slide-menu li a').on('click', function(){
$(this).parent().addClass('current').siblings().removeClass('current');
});
});
.container {
float: left;
}
.display-item {
display: none;
}
.display-item:first-of-type {
display: block;
}
.slide-menu li.current a {
color: #75aaaf;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="container">
<ul class="slide-menu" id="first">
<li class="current">1348</li>
<li>1558</li>
<li>1590</li>
</ul>
<div class="display-item history" id="1348" style="display:block;">History Content</div>
<div class="display-item history" id="1558">History Content2</div>
<div class="display-item history" id="1590">History Content3</div>
</div>
<div class="container">
<ul class="slide-menu" id="second">
<li class="current">Introduction</li>
<li>Highways</li>
<li>Transport</li>
</ul>
<div class="display-item vision" id="base" style="display:block;">Vision Content</div>
<div class="display-item vision" id="highways">Vision Content2</div>
<div class="display-item vision" id="transport">Vision Content3</div>
</div>
I think your code is okay if you intend duplicating the first toggle function in toggle2 function all you have to do is
Change the onclick event function from toggle to toggle2
<div class="container">
<ul class="slide-menu" id="second">
<li class="current"><a href="#/"
onclickk="toggle2('base');">Introduction</a></li>
<li><a href="#/"
onclick="toggle2('highways');">Highways</a></li>
<li><a href="#/"
onclick="toggle2('transport');">Transport</a></li>
</ul>
<div class="display-item vision" id="base"
style="display:block;">Vision Content</div>
<div class="display-item vision" id="highways">Vision
Content2</div>
<div class="display-item vision" id="transport">Vision
Content3</div>
</div>
This really isn't the way to set this up as it just causes the code to grow as more items need to be shown/hidden and the new code is largely the same as the old code. The original code also is more complex than it need be.
The following code will work no matter how many container structures you put on the page as long as you keep the structure the same as it is now. No ids are needed. No JQuery is needed either. You'll never need to touch the JavaScript, just add/remove HTML containers as you see fit.
See comments inline for details on what's happening.
.container {
float: left;
border:1px solid #e0e0e0;
margin:10px;
width:25%;
padding:3px;
}
/* Don't use hyperlinks <a></a> when you aren't
navigating anywhere. If you just need something
to click on, any element will do.
We'll just style the clickable elements to look like links
*/
.slide-menu > li {
text-decoration:underline;
cursor:pointer;
color: #75aaaf;
}
.hidden { display: none; } /* This class will be toggled upon clicks */
<!--
Don't use hyperlinks <a></a> when you aren't
navigating anywhere. If you just need something
to click on, any element will do.
The elements that should be hidden by default
will be so because of the "hidden" class that
they start off with.
No JQuery needed for this. Keep the HTML clean and
do all the event binding in JavaScript (no onclick="...")
-->
<div class="container">
<ul class="slide-menu">
<li class="current">1348</li>
<li>1558</li>
<li>1590</li>
</ul>
<div class="history" id="1348">History Content</div>
<div class="history hidden" id="1558">History Content2</div>
<div class="history hidden" id="1590">History Content3</div>
</div>
<div class="container">
<ul class="slide-menu">
<li class="current">Introduction</li>
<li>Highways</li>
<li>Transport</li>
</ul>
<div class="vision" id="base">Vision Content</div>
<div class="vision hidden" id="highways">Vision Content2</div>
<div class="vision hidden" id="transport">Vision Content3</div>
</div>
<!-- The following function will run automatically when this script element
is reached. Always keep the script just before the closing body tag (</body>). -->
<script>
(function(){
// Get any/all slide-menu elements into an array
let menus =Array.prototype.slice.call(document.querySelectorAll(".slide-menu"));
// Loop over the menus
menus.forEach(function(menu){
// Loop over the list items in the menu
Array.prototype.slice.call(menu.querySelectorAll("li")).forEach(function(item, index){
let idx = index;
// Set up a click event handler for each item
item.addEventListener("click", function(){
// Get all the <div> items in this menu into an Array
let divs = Array.prototype.slice.call(menu.parentElement.querySelectorAll("div"));
// Hide any item that was previously showing
divs.forEach(function(div){ div.classList.add("hidden"); });
// Query the parent element (the container) for all the
// corresponding <div> items and make it visible
divs[idx].classList.remove("hidden");
});
});
});
}());
</script>

Javascript show/hide, show first div on page load

Can you help me to make the first div show on page load?
function showStuff(element) {
var tabContents = document.getElementsByClassName('tabContent');
for (var i = 0; i < tabContents.length; i++) {
tabContents[i].style.display = 'none';
}
var tabContentIdToShow = element.id.replace(/(\d)/g, '-$1');
document.getElementById(tabContentIdToShow).style.display = 'block';
}
.tabContent {
display:none;
}
<div tabindex="1" class="tabs"><div id="tabs1" onclick="showStuff(this)">CARATTERISTICHE</div><div class="triangle-down-tab"></div></div>
<div id="tabs2" onclick="showStuff(this)">DESTINATARI</div><div class="triangle-down-tab"></div></div>
<div tabindex="3" class="tabs"><div id="tabs3" onclick="showStuff(this)"><i class="fa fa-calendar" style="color:#000000;"></i> CALENDARIO</div><div class="triangle-down-tab"></div></div>
<a name="contenuto"><hr></a>
<div id="tabs-1" class="tabContent">
<p>tab 1</p>
</div>
<div id="tabs-2" class="tabContent">
<p>tab 2 tab 2 </p>
</div>
<div id="tabs-3" class="tabContent">
<p>tab 3 tab 3 tab 3</p>
</div>
This is my actual code. jsFiddle
Thanks!
You could try running a function when the document is ready.
$(document).ready(function () {
showTab("tabs-1");
function showTab(divId) {
//Get the element
var divElement= document.getElementbyId(divId);
//Set the css property "display" from "none" to be "block";
divElement..style.display = "block";
}
}):
The function should run once the page has fully loaded.
Let me know how it goes.
I sure can. When you do this kind of stuff best use css. That way when the dom loads the css will kick in and your desired effect will show.
Further more its easier to understand and easier to code up.
.tabContent {
display:none;
}
.tabContent.active {
display:block;
}
Then in the HTML
<div id="tabs-1" class="tabContent active">
So when the page loads tab one is active
Then in your JS
function showStuff(element) {
var tabContents = document.getElementsByClassName('tabContent');
for (var i = 0; i < tabContents.length; i++) {
tabContents[i].className="tabContent";
}
var tabContentIdToShow = element.id.replace(/(\d)/g, '-$1');
document.getElementById(tabContentIdToShow).className="tabContent active";
}
Updated fiddle!
https://jsfiddle.net/rb5c5095/3/
We could improve things since we know all the tabs will be made invisible at boot up and tab 1 will show. So when a tab is clicked we could just search the tab who has .active class and remove it, then apply the .active class to the new tab. This would have the benefit that any extra css you add in your html markup would not be removed by the JS code, but i reckon you can work that out and if you can't get back to me i can show you :-)
Here I am invoking the function (upon page load) that tweaks the css of the desired block;
Same can be achieved by $(document).ready;
I took this approach to avoid jquery;
window.onload = showDivOne();
function showDivOne() {
document.getElementById("tabs-1").style.display = "block";
}

Categories