Close menu with click off menu itself - javascript

I'm not the best when it comes to JavaScript, and stuck with finding a solution. I have seen similar questions asked here, but when I try to implement it in my case it either breaks the menu or just makes no difference.
I'm trying to get a menu (which opens on a click), to close not only with a repeated click on parent menu tab, but with a click outside the menu, i.e., anywhere.
My code is:
var toggleUpdatesPulldown = function(event, element, user_id) {
if( element.className=='updates_pulldown' ) {
element.className= 'updates_pulldown_active';
showNotifications();
} else {
element.className='updates_pulldown';
}
}
This snippet is in the middle of a lot more JavaScript and this is the default working version. The click from user changes the class name of the menu container which determines if it's displayed or not. From another post on here, I tried implementing the following to no avail to try and allow the click off to alter the class name as well:
var toggleUpdatesPulldown = function(event, element, user_id) {
if( element.className=='updates_pulldown' ) {
element.className= 'updates_pulldown_active';
showNotifications();
} else {
element.className='updates_pulldown';
}
ev.stopPropagation();
$(document).one('click', function() {
element.className='updates_pulldown';
});
}
Any advice on tackling this? I'd like to learn more JavaScript as I seem to be working with it more and more.

I hope you are still looking for a solution. Here's a working demo of this http://jsfiddle.net/sU9ZJ/6/
(function(win, doc) {
var lis = $('#menu>ul>li>a').on('click', function(e) {
e.preventDefault();
var a = $(this);
var li = $(this).parent();
function close(dev) {
if (!(dev && li.has(dev.target)[0])) {
li.addClass('inactive').removeClass('active');
doc.off('click', close);
a.trigger('close');
}
}
function open(dev) {
li.addClass('active');
doc.on('click', close);
a.trigger('open');
}
if (li.hasClass('active')) { close() }
else { open(); }
})
})(this, $(document))
I have also added a couple of events that you can use when it opens or closes
$('#menu>ul>li>a').on('open', function(e) {
console.log('menu open', this)
}).on('close', function(e) {
console.log('menu closed', this)
})
Sorry, this depends on jQuery. too lazy to write a native version :). Also this is not tested in IE, but shouldn't be too hard to make it work on those if it doesn't.

Related

Show a sub-menu using JQuery

I need some help making a sub-menu appear within 2s after the page loads instead of when the user clicks on it. I'm using JQuery. That file is the core of the website. I need it to stay opened.
Here's the code I have at the moment, I tried to change that on.Click event but it didn't work.
The handleSidenarAndContentHeight(); function resizes the menu items after the sub-menu appears.
jQuery('.page-sidebar li > a').on('click', function (e) {
if ($(this).next().hasClass('sub-menu') === false) {
return;
}
var parent = $(this).parent().parent();
parent.children('li.open').children('a').children('.arrow').removeClass('open');
parent.children('li.open').children('a').children('.arrow').removeClass('active');
parent.children('li.open').children('.sub-menu').slideUp(350);
parent.children('li').removeClass('open');
parent.children('li').removeClass('active');
var sub = jQuery(this).next();
if (sub.is(":visible")) {
jQuery('.arrow', jQuery(this)).removeClass("open");
jQuery(this).parent().removeClass("active");
sub.slideUp(350, function () {
handleSidenarAndContentHeight();
});
} else {
jQuery('.arrow', jQuery(this)).addClass("open");
jQuery(this).parent().addClass("open");
sub.slideDown(350, function () {
handleSidenarAndContentHeight();
});
}
e.preventDefault();
});
Working with a 2 second timeout should do the trick!
jQuery(document).ready(function(){
// Open Parent here
setTimeout(function(){
// Open Child here
}, 2000)
});
There is a simple javascript function you can use, the setTimeout function.
The code follows like this :
setTimeout(function() {yourFunctyion();}. delayTimeInMiliseconds);
This will call your function after the number of second(in ms).
There is also a plugin I've used. It has oneTime and everyTime methods.
jQuery timers plugin

can I make a function into a variable to reduce my code (JavaScript Code debug Please)

Hello I have been boggling my mind over and over again trying to simplify this java Script Code.
I am fairly new to JavaScript and I do not know where else to turn.
I am making a navigation that when I click on a button it will animate to transform:translateX(0); from transform:translateX(-98%); as a class.
I am also making it if you hover over the div .main-navigation it will slide back and forth accordingly. I have it where the mouseover will slide the navigation if its open to the close state but I cannot do so when it is closed to open. I am also trying to make it if the .home is active then the hover will not open or close the .home just the menu.
Any suggestions?
$(function(){
var navToggle = document.querySelectorAll('.nav-toggle');
var mainMenu = document.querySelectorAll('.main-navigation');
$(navToggle).on('click', function(){
if ($(mainMenu).hasClass('close')){
$(mainMenu).removeClass('close');
$(mainMenu).addClass('open');
}else{
$(mainMenu).addClass('close');
$(mainMenu).removeClass('open');
};
$('.home').toggleClass('hide, toggleAnimate');
$('.contentWrap').toggleClass('open');
});
$(mainMenu).on('mouseenter', function(){
if ($(mainMenu).hasClass('close')){
$(mainMenu).removeClass('close');
$(mainMenu).addClass('open');
}
if ($(mainMenu).hasClass('open')){
$(mainMenu).removeClass('open');
$(mainMenu).addClass('close');
};
});
});
Sorry I created a Code Pen to show you a very close example of what I am trying to do and the behavior that is happening.
My CodePen Example
Never mind I figured it out, I went with JQuery and was able to achieve my goal. I ended up changing it to this.
$(function(){
homeAnimate();
menuAnimate();
menuAnimate2();
autoAnimateEnter();
autoAnimateExit();
function homeAnimate(){
$('.nav-toggle').click(function () {
$('.home').toggleClass('hide, toggleAnimate');
$('.contentWrap').toggleClass('open');
});
}
function menuAnimate(){
$('.nav-toggle').click(function () {
if ($('.main-navigation').hasClass('close')) {
$('.main-navigation').addClass('close');
$('.main-navigation').toggleClass('open');
}
if ($('.main-navigation').hasClass('open')) {
$('.main-navigation').toggleClass('close');
$('.main-navigation').toggleClass('open');
}
});
}
function menuAnimate2(){
$('.nav-toggle-menu').click(function () {
if ($('.main-navigation').hasClass('open')) {
} else {
$('.main-navigation').addClass('open');
$('.main-navigation').removeClass('close');
}
$('.home').toggleClass('hide, toggleAnimate');
$('.contentWrap').toggleClass('open');
});
}
function autoAnimateEnter(){
$('.main-navigation').mouseenter(function () {
if ($('.main-navigation').hasClass('close')) {
$('.main-navigation').removeClass('close');
$('.main-navigation').addClass('open');
} else {
// DO NOTHING
}
});
}
function autoAnimateExit(){
$('.main-navigation').mouseleave(function () {
if ($('.home').hasClass('toggleAnimate')) {
// DO NOTHING
} else {
$('.main-navigation').removeClass('open');
$('.main-navigation').addClass('close');
}
});
}
});
I'm not sure if this is the cleanest way in order to achieve my goal but it works and I'm happy.
Here is my code if anyone wants to check it out.
Code

Javascript ignoring if statements

I'm somewhat new to Javascript. I'm trying to make it so that clicking on an image on one page takes you to a new page and shows a specific div on that new page, so I used sessionStorage to remember and booleans to keep track of which image is being clicked. Right now, the code always executes the first if statement, regardless of which image is clicked. This code works fine in normal java so I can't figure out why my if statements are being ignored in javascript. I also tried adding an 'else' at the end, and tried ===. Here's my javscript, and thank you!
sessionStorage.clickedLeft;
sessionStorage.clickedMiddle;
sessionStorage.clickedRight;
function openedProjectFromGallery() {
if(sessionStorage.clickedLeft) {
$(".left-project-pop-up").show();
} else if (sessionStorage.clickedMiddle) {
$(".middle-project-pop-up").show();
} else if (sessionStorage.clickedRight) {
$(".right-project-pop-up").show();
}
sessionStorage.clickedLeft = false;
sessionStorage.clickedMiddle = false;
sessionStorage.clickedRight = false;
}
$("document").ready(function () {
$(".pop-up .x-button").click(function(){
$(".pop-up").hide();
});
$(".project-description .x-button").click(function(){
$(".project-pop-up").hide();
});
$(".left-project-thumb img").on("click", ".left-project-thumb img", function(){
sessionStorage.clickedLeft = true;
sessionStorage.clickedMiddle = false;
sessionStorage.clickedRight = false;
openedProjectFromGallery();
});
$(".profile-left-project img").click(function(){
$(".left-project-pop-up").show(1000);
});
$(".middle-project-thumb img").on("click", ".middle-project-thumb img", (function(){
sessionStorage.clickedMiddle = true;
sessionStorage.clickedLeft = false;
sessionStorage.clickedRight = false;
openedProjectFromGallery();
});
$(".profile-middle-project img").click(function(){
$(".middle-project-pop-up").show(1000);
});
$(".right-project-thumb img").on("click", ".right-project-thumb img", (function(){
sessionStorage.clickedRight = true;
sessionStorage.clickedLeft = false;
sessionStorage.clickedMiddle = false;
openedProjectFromGallery();
});
$(".profile-right-project img").click(function(){
$(".right-project-pop-up").show(1000);
});
});
You are defining function openedProjectFromGallery() with in document.ready . Define it outside document.ready and also give your three booleans some initial value at the top of your code if not initialized with some value or they are empty. I hope this would help.
It is not really answer to your orginal question,as the main issue with your code is, as #njzk2 says, that openProjectFromGallery only being called once, and not on each event, however I wanted to put my two coins on how this code could look like.
This is good example where custom events should be used
$(document).on('showPopup', function( e, popup ) {
$('.'+popup + '-project-pop-up').show()
})
$(document).on('hidePopup', function( e ) {
$('.popup').hide()
})
$('.left-project-thumb img').on('click', function(e) {
$(document).trigger('showPopup', ['left'])
})
$('.right-project-thumb img').on('click', function(e) {
$(document).trigger('showPopup', ['right'])
})
I think you get an idea.
On the other hand, it always nice to use event delegation with a lot of similar events as well as dom data.
<div class='popup' data-popup='left'>
<img />
</div>
$(document).on('click','.popup', function( e ) {
$(document).trigger('showPopup', [$(this).data('popup')])
})
From what I can see openedProjectFromGallery is only getting called on document load.
Add a call to it into each of the event handling functions or use jQuery's delegate function to assign event handling to each image.

jQuery function for app style slide in menus

My name is Adam, I'm new to Stack Exchange, but have found this site very useful for many past problems I have had.
I'm having a problem with a jquery function and thought I'd seek advice here. I have a pretty decent knowledge of html & css, a little of php, but virtually none of javascript or jquery.
I'm currently working on a site that uses specific html tags to enable dynamic content as php isn't permitted. Javascript is however so I've been looking it. I don't have a live example to show you here as I can only preview the design from within my account, however I have pasted the script below.
I wanted to create a responsive design, fluid down to mobile. Following recent design trends, I wanted to create 'Slide in/out' style menus from the side of the screen (think Facebook Mobile, Dolphin Browser). After viewing some examples, I wrote a function which altered the CSS, moving the main div#site template to the right, revealing the left menu. Everything was ok and it worked fine.
Today I decided it would be nice to have 2 slide out menus, one on the left, the other, on the right.
I added to the function what I thought was going to work, and it sort of does.
I have a button (with class .open-sidebar-right) to slide the main site (div#site) to the left, revealing the right hand menu. I can then click either the same button or the div#site to close the menu.
The problem occurs when I click on the left button. The left menu opens and closes absolutely perfectly, however it renders the right button totally useless and doesn't function at all.
I've tried writing it as two separate functions, using one variable for both menus with different values, and it always renders the right button useless after using the left button.
As I mentioned earlier, I have virtually no knowledge of Javascript or jQuery, so it's probably poorly coded, but I can't understand why this wouldn't work.
If anyone has any advice or suggestions I would really appreciate it.
Thanks in advance, Adam.
jQuery(function () {
var sidebarleft;
var sidebarright;
// ------------
// Left sidebar
jQuery(".open-sidebar-left").click(function () {
if (!sidebarleft) {
jQuery("#site").css({
'left':'50%',
});
sidebarleft = true;
return false;
} else {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
}
});
// ------------
// Right sidebar
jQuery(".open-sidebar-right").click(function () {
if (!sidebarright) {
jQuery("#site").css({
'right':'50%',
});
sidebarright = true;
return false;
} else {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
// ----------------------------------
// Close sidebars by clicking on site
jQuery("#site").click(function () {
if (sidebarleft) {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
} else if (sidebarright) {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
});
Adam,
#zgood says your code is good, but I thought I'd point out a few errors and make some suggestions which may solve your problem:
$(document).ready(function(){ // in the jQuery doc, they don't suggest you use $(<func>)
var sidebarleft = false, // sidebarleft and sidebarright has to be equal to something
sidebarright = false; // either true or false (I would use false since you're testing false in your conditional
$(".open-sidebar-left").click(function() {
if( !sidebarleft ) {
$("#site").css({
left: '50%' // remove the comma, and do not put quotes around single-word identifiers
});
sidebarleft = true;
return false;
} else {
$("#site").css({
left: '0'
});
sidebarleft = false;
return false;
}
});
$(".open-sidebar-right").click(function() {
if( !sidebarright ) {
$("#site").css({
right: '50%' // remove the comma, and do not put quotes around single-word identifiers
});
sidebarright = true;
return false;
} else {
$("#site").css({
right: '0'
});
sidebarright = false;
return false;
}
});
});
So as you can see in the comments in the code above,
jQuery says it's valid, but not suggested that you use jQuery(function(){}); so query the document element then test for ready, then call a function
sidebarright and sidebarleft were undefined (neither true or false) so your
if statements don't make sense.
In the css() declaration, you shouldn't put a comma on the last element. Only put commas if there are more than one element.
I would also suggest using animate() instead of css(), and also (if you're using Chrome) use the inspector and (if you're using Firefox) use FireBug to test for any errors in your javascript code. Hope this helps.
Your code is right, the problem seems to be a CSS issue.
When you click your left button your click event is adding an inline style to your #site div like so:
<div id="site" style="left:50%;">
Then when you click your right button your code appends the new style to your #site div like so:
<div id="site" style="left: 0%; right: 50%;">
See the problem?
To fix this you must do two things. Since you didn't post your CSS, I don't know how you have your #site styled, but remove any left or right style from your #site style declaration.
Next update your jQuery code to remove any previous inline styles like so:
// ------------
// Left sidebar
jQuery(".open-sidebar-left").click(function () {
jQuery("#site").removeAttr('style');
if (!sidebarleft) {
jQuery("#site").css({
'left':'50%',
});
sidebarleft = true;
return false;
} else {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
}
});
AND
jQuery(".open-sidebar-right").click(function () {
jQuery("#site").removeAttr('style');
if (!sidebarright) {
jQuery("#site").css({
'right':'50%',
});
sidebarright = true;
return false;
} else {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
removeAttr is your friend here. Also you may want to use an animate instead of just changing the css values, but thats your call
jQuery .animate()

How to retain Javascript state on page change

I have an accordion style navigation list set up so that when categories are clicked it opens up to show sub-categories that link to pages.
What I would like to do is have the accordion navigation list keep it's open or closed state when the new page opens.
I've gathered that cookies work to retain the state on refresh, but how do I retain the state when a different page is visited? All the pages have the same accordion navigation list.
Try Web Storage. Store the state of the tabs on page unload, restore the state on the page load event.
I found a solution, it uses the accordian plug-in found here, http://www.i-marco.nl/weblog/archive/2010/02/27/yup_yet_another_jquery_accordi and the jquery cookie.js plug-in
I added id's to the header anchor tages in the HTNL mark-up like so,
<li>
<a id="m1" class="label" href="#">Sound/Audio Systems</a>
<ul class="acitem">
<li>PA Systems</li>
<li>Loudspeakers</li>
<li>Microphones </li>
<li>DJ Equipment</li>
<li>Sound Processing Equipment</li>
</ul>
</li>
And modified the accordian.js code, I added the lines beginning with $.cookie, and the If statement in the document.ready funciton.
jQuery.fn.initMenu = function() {
return this.each(function(){
var theMenu = $(this).get(0);
$('.acitem', this).hide();
$('li.expand > .acitem', this).show();
$('li.expand > .acitem', this).prev().addClass('active'),
currentID = "";
$('li a', this).click(
function(e) {
e.stopImmediatePropagation();
var theElement = $(this).next();
var parent = this.parentNode.parentNode;
if($(parent).hasClass('noaccordion')) {
if(theElement[0] === undefined) {
window.location.href = this.href;
}
$(theElement).slideToggle('normal', function() {
if ($(this).is(':visible')) {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
}
else {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
});
return false;
}
else {
if(theElement.hasClass('acitem') && theElement.is(':visible')) {
if($(parent).hasClass('collapsible')) {
$('.acitem:visible', parent).first().slideUp('normal',
function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
);
return false;
}
return false;
}
if(theElement.hasClass('acitem') && !theElement.is(':visible')) {
$('.acitem:visible', parent).first().slideUp('normal', function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
});
theElement.slideDown('normal', function() {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
});
return false;
}
}
}
);
});
};
$(document).ready(function() {
$('.menu').initMenu();$('#side-navigation_frame').show();
if ($.cookie('menustate')) {
var anchor = "",
elementID = $.cookie('menustate');
anchor = document.getElementById(elementID);
$(anchor).addClass('active');
$(anchor).next().show();
}
});
It works nicely, not bad for a beginner, thanks for all the advise.
Rob Fenwick
Cookies "retain state" across the full path and domain for which they are specified. So if you can get them to work for just one page, you should have them work automatically on all pages of your site.
You can still use cookies, you just have to make sure they're not specific to the one page. For example:
document.cookie = 'openitem=5; expires=somedate; path=/';
will be accessible to all pages on the site. More about cookies.
Ok so I took a look at the library you are using, it's a decent library and all but you might find it easier to find solutions to your problems if you use a more standard library like jQuery UI, it has an accordion control http://jqueryui.com/demos/accordion/ and like I mentioned there are so many people using it that the answer to most problems can be found.
But like I mentioned I did take a look at your library. As others have mentioned you would use a cookie to store the value. This library supports 'pre expanding' a particular section of the accordian, to do that you would add the expand class to the element. You can either do that server side or you can do it using JavaScript before initMenu() is called.
The other less elegant option is to trigger the click event on the anchor tag after the call to initMenu. Finally you can use jQuery's show() to show expand the section without animation.
The first thing you have to do is find out which section was clicked on, then you would store that sections name in a cookie. On page load you would get that value and expand the appropriate according section. This is what the code should kinda look like - note this is psuedo code and you have fill in the appropriate parts.
$(function() {
$(".menu.collapsible .label").click(function() {
var accordianSection = $(this).text();
rememberSection(accordianSection);
});
var section = recallSection();
if(section !== undefined) {
expandSection(section);
}
});
The expandSection function can look something like this:
var sectionLink = $(".menu.collapsible .label").filter(function() {
return $(this).text() == section;
});
sectionLink.trigger('click');

Categories