Why does my onclick hamburger button stop working after event? - javascript

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

Related

simplifying a javascript click count menu controlling 3 individual dropdowns

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 -->

Displaying a block on mouseover inline

I want to display a <div> block when mouse enters an element
My code so far:
<div class="dropdown">
MEN
<div class="dropdowncontent" id="ddmen" style="margin-left:100px;">
TOPWEAR <br/>
BOTTOMWEAR </br>
FOOTWEAR
</div>
</div>
JavaScript Code:
var ddm=document.getElementById("ddmen")
function ddmenin()
{
ddm.style.display="block";
}
function ddmenout()
{
ddm.style.display="none";
}
But when i hover over <a href="#men"> I cannot click on the links in the <div> with class="dropdowncontent" as the block disappears when i leave the <a href="#men">
I don't understand why this is happening since i have used onmouseover, which is valid even for child elements.
I have tried doing it using css but for some reason the following does not work (Style.css is used in above html)
STYLE.CSS
.dropdowncontent{
display:none;
}
.dropdown:hover .dropdowncontent{display:block;}
Can someone please correct my code to satisfy my needs or has any other simple alternative?
Well, your div link container is not part of a link, so when you move cursor to dropdown menu you leave the link and onmouseout listener does its job.
What you want is to hide the menu when it's not needed anymore. E.g. you clicked on the menu item or you left the menu and didn't return for some time.
To achieve this you can do the following:
Add hiding the menu to click listener on menu items
Add a function that starts some timer as soon as you leave the dropdown button or the menu (so that makes two onmouseout listeners). If you return there, you can reset the timer in onmouseover. When timer is done you can hide the menu.
It can look like this:
const $ = document.querySelector;
let menuTimeoutId;
const menu = $('#ddmen');
function stopMenuTimeoutAndShowMenu() {
if (menuTimeoutId) {
clearTimeout(menuTimeoutId);
menuTimeoutId = null;
}
menu.style.display = 'block';
}
function startMenuTimeout() {
window.menuTimeoutId = setTimeout(() => {
menu.style.display = 'none';
}, 2000); // possible timeout value
}
$('#men, #ddmen').addEventListener('onmouseover', stopMenuTimeoutAndShowMenu);
$('#men, #ddmen').addEventListener('onmouseout', startMenuTimeout);
I think you should use the onmouseover and onmouseout in your <div class="dropdown"> instead. Because, when you go to the div.dropdowncontent you probably invokes the onmouseout event. So the code will be like this:
<div class="dropdown" onmouseover="ddmenin()" onmouseout="ddmenout()">
MEN
<div class="dropdowncontent" id="ddmen" style="margin-left:100px;">
TOPWEAR <br/>
BOTTOMWEAR </br>
FOOTWEAR
</div>
</div>
See if it works ;D
You can try simple CSS changes, that can even help you :
In your Style.css file:
.dropdown .dropdowncontent {
visibility: hidden;
}
.dropdown:hover .dropdowncontent {
visibility: visible;
}

Jquery show/hide divs - fix overlapping animations

I am using JS to show/hide divs via clicking on the side nav with jquery functions fadeIn() and fadeOut(). The problem I run into is as one div fades out, the next is fading in simultaneously. Also, if I click the link for the div that is already shown, it fades out and fades in again. I'm not sure if an IF statement would be the best approach to do two fixes:
1. Let shown div fully fadeOut before next starts to fadeIn.
2. Currently shown div will not fadeOut/In if same link is clicked.
Here is what I have thus far (without my broken attempt at an IF statement):
http://jsfiddle.net/k55Cw/1/
HTML:
<div class="container">
<header>
<ul class="sidenav">
<li><h2><a data-region="nav-1" href="#">About</a></h2></li>
<li><h2><a data-region="nav-2" href="#">Services</a></h2></li>
<li><h2><a data-region="nav-3" href="#">Team</a></h2></li>
<li><h2><a data-region="nav-4" href="#">News</a></h2></li>
<li><h2><a data-region="nav-5" href="#">Contact</a></h2></li>
</ul>
</header>
<div id="nav-1" class="infozone"><p>Hello I'm box 1.</p></div>
<div id="nav-2" class="infozone"><p>Hello I'm box 2.</p></div>
<div id="nav-3" class="infozone"><p>Hello I'm box 3.</p></div>
<div id="nav-4" class="infozone"><p>Hello I'm box 4.</p></div>
<div id="nav-5" class="infozone"><p>Hello I'm box 5.</p></div>
</div>
CSS:
.infozone{
float:left;
height:400px;
width:800px;
background-color: #000;
display:none;
}
JS:
$(document).ready(function() {
$('.sidenav a').click(function(){
$('.infozone').fadeOut(850);
var region = $(this).attr('data-region');
$('#' + region).fadeIn(850);
});
});
to chain the animations put the fadeIn inside the callback for fadeOut, and to cancel the function if it's currently shown, check if the div is already visible.
I've also had to add a check to see if the current .infozone div is visible - or else the fadeOut applies to hidden elements too, and the callback fires multiple times:
$(document).ready(function() {
$('.sidenav a').click(function(){
var region = $(this).attr('data-region');
var $region = $('#' + region);
if ($region.is(':visible')) return;
var $infozone = $('.infozone:visible');
if ($infozone.length === 0) {
$region.fadeIn(850);
} else {
$infozone.fadeOut(850, function() {
$region.fadeIn(850);
});
}
});
});
You could something like that:
html
This make you page works when javascript is disabled:
<header>
<ul class="sidenav">
<li><h2>About</h2></li>
<li><h2>Services</h2></li>
<li><h2>Team</h2></li>
<li><h2>News</h2></li>
<li><h2>Contact</h2></li>
</ul>
</header>
note that the href point to the id you want to show. This will works also for screen reader if you want to make your page accessible.
javascript. I have not tested it, you might have to fix few things, but the idea is there
$(document).ready(function() {
$('.sidenav a').click(function(e){
var href = $(this).attr('href');
// prevent default
e.preventDefault();
// prevent clicked twice
if(!$(this).hasClass('active'){
$('.sidenav a').removeClass('active');
$(this).addClass('active'){
$('.infozone').fadeOut(850);
$(href.substring(1)).fadeIn(850);
}
});
You should also consider adding some ARIA attributes and roles attributes.

How to fix a jquery .animate margin slider?

My website is: http://www.grozav.com
I need help in repairing the code at the thumbnail slider part (Portfolio). If someone clicks the arrow twice, really fast, it gets off track, and the coding stops working.
HTML Markup:
<div id="portfolio">
<div id="up-arrow">UP</div>
<div id="thumbnails">
<div id="slider">
thumbnails go here
</div>
</div>
<div id="down-arrow">DOWN</div>
</div>
Jquery:
$('#up-arrow a').stop().click(function(){
if($('#slider').css("margin-top")!='0px' ){
$('#slider').stop().animate({'margin-top':'+=360px'})
$('#down-arrow').css({'background-position':'0 0px'})
$('#down-arrow a').css({'cursor':'pointer'})
//CHANGE <='PX' VALUE FOR NEXT SLIDE
if($('#slider').css("margin-top")<='-360px'){
$('#up-arrow').css({'background-position':'0 -28px'})
$('#up-arrow a').css({'cursor':'help'}) }
$('#down-arrow').css({'background-position':'0 0px'})
}
else if ($('#slider').css("margin-top")>'0px') {
$('#slider').css({'margin-top':'0px'});
}
});
$('#down-arrow a').stop().click(function(){
if($('#slider').css("margin-top")!='-720px' || $('#slider').css("margin-top")<'-720px'){
$('#slider').stop().animate({'margin-top':'-=360px'})
$('#up-arrow').css({'background-position':'0 0px'})
$('#up-arrow a').css({'cursor':'pointer'})
//CHANGE <='PX' VALUE FOR NEXT SLIDE
if($('#slider').css("margin-top")<='-360px'){
$('#down-arrow').css({'background-position':'0 -27px'})
$('#down-arrow a').css({'cursor':'help'}) }
$('#up-arrow').css({'background-position':'0 0px'})
}
else if ($('#slider').css("margin-top")<'-720px') {
$('#slider').css({'margin-top':'-360px'});
}
});
It changes the button aspect when it's at the beginning and at the end of the slides. I coded it this way due to lack of knowledge in the sliders domain.
How can I fix it, or at least prevent it from clicking twice?
Why not wrap your function in an if condition that checks to see if the slider is being animated? Then they'll only work when the animation is not occurring.
Something like if( !$('#slider').is(':animated') ){ ... your code ... }

Conflict between some JavaScript and jQuery on same page

I am using a JavaScript function and some jQuery to perform two actions on a page. The first is a simple JS function to hide/show divs and change the active state of a tab:
This is the JS that show/hides divs and changes the active state on some tabs:
var ids=new Array('section1','section2','section3');
function switchid(id, el){
hideallids();
showdiv(id);
var li = el.parentNode.parentNode.childNodes[0];
while (li) {
if (!li.tagName || li.tagName.toLowerCase() != "li")
li = li.nextSibling; // skip the text node
if (li) {
li.className = "";
li = li.nextSibling;
}
}
el.parentNode.className = "active";
}
function hideallids(){
//loop through the array and hide each element by id
for (var i=0;i<ids.length;i++){
hidediv(ids[i]);
}
}
function hidediv(id) {
//safe function to hide an element with a specified id
document.getElementById(id).style.display = 'none';
}
function showdiv(id) {
//safe function to show an element with a specified id
document.getElementById(id).style.display = 'block';
}
The html:
<ul>
<li class="active"><a onclick="switchid('section1', this);return false;">ONE</a></li>
<li><a onclick="switchid('section2', this);return false;">TWO</a></li>
<li><a onclick="switchid('section3', this);return false;">THREE</a></li>
</ul>
<div id="section1" style="display:block;">TEST</div>
<div id="section2" style="display:none;">TEST 2</div>
<div id="section3" style="display:none;">TEST 3</div>
Now the problem....
I've added the jQuery image gallery called galleria to one of the tabs. The gallery works great when it resides in the div that is intially set to display:block. However, when it is in one of the divs that is set to display: none; part of the gallery doesn't work when the div is toggled to be visible. Specifically, the following css ceases to be written (this is created by galleria jQuery):
element.style {
display:block;
height:50px;
margin-left:-17px;
width:auto;
}
For the life of me, I can't figure out why the gallery fails when it's div is set to display: none. Since this declaration is overwritten when a tab is clicked (via the Javascript functions above), why would this cause a problem? As I mentioned, it works perfectly when it lives the in display: block; div.
Any ideas? I don't expect anybody to be familiar with the jQuery galleria image gallery... but perhaps an idea of how one might repair this problem?
Thanks!
If you are including jQuery then you can shorten your javascript to this:
$(function() {
var sections = $('#section1, #section2, #section3');
function switchid(id, el){
sections.hide();
$('#'+id).show();
$(this).addClass('active').closest('ul').find('li').removeClass('active');
}
});
I would also remove the inline styles that set display:none. Then you can in your javascript you can initialize galleria then hide your sections.
Something like:
$(function() {
$('#section2, #section3').hide();
$('#section2 .images').galleria();
var sections = $('#section1, #section2, #section3');
function switchid(id, el){
sections.hide();
$('#'+id).show();
$(this).addClass('active').closest('ul').find('li').removeClass('active');
}
});
I would even go further and change your html to be something like this:
<ul class="sectionlinks">
<li class="active">ONE</li>
<li>TWO</li>
<li>THREE</li>
</ul>
<div id="section1" class="section">TEST</div>
<div id="section2" class="section">TEST 2</div>
<div id="section3" class="section">TEST 3</div>
Then you javascript could just be:
$(function() {
$('#section2 .images').galleria();
$('#section2, #section3').hide();
var sections = $('.section');
$('.sectionlinks a').click(function(e){
e.preventDefault();
sections.hide();
$($(this).attr('href')).show();
$(this).closest('ul').find('li').removeClass('active');
$(this).closest('li').addClass('active');
});
});
Working example: http://jsfiddle.net/cdaRu/2/
Set them all to 'block' by default, initialize the galleria image gallery, and afterwards hide the divs you want hidden and see if that fixes it. Or try initializing the gallery again after every switchid.
My first recommendation would be to re-write your original Javascript function to use jQuery. It already has built-in visibility toggle functions ... using the same system will minimize conflicts and make for smoother code.
This is just "off the cuff" but perhaps the box model is incomplete: "The element will generate no box at all" with display: none;
Perhaps change that back to "block" and set visibility: hidden; would be better?

Categories