Animate icon don't take his original position on toggle click - javascript

I have a accordion menu which have for each parent menu a icon, and this icon is animated with css transition and transform. I added a class with a if condition to the click event. The problem is that when I click for example on Menu1, the icon animation does very well, but if I click directly on Menu2, the menu2 dropdown appear but icon from the menu1 don't take his original position.
This problem applies to each icon in each menu/submenu, I thinks that I have a mistake in my code.
$(document).ready(function() {
// Icons effect
$('#mw_nav .toggle').click(function() {
if($(this).hasClass('rotate_close'))
{
$(this).addClass('rotate_open').removeClass('rotate_close');
}
else {
$(this).addClass('rotate_close').removeClass('rotate_open');
}
});
// Toggle Menu Items
$(function () {
$("#m_nav > ul ul").hide();
$('#m_nav .toggle').click(function (e) {
e.preventDefault();
e.stopPropagation();
var $parentli = $(this).closest('li');
$parentli.siblings('li').find('ul:visible').slideToggle(400);
$parentli.find('> ul').stop().slideToggle(400);
$(this).remove;
});
});
});
FIDDLE
Any help would be appreciated

There are 2 issues I see with your code. The first is a recommendation to NOT have $(function() { // your code }) inside of $(document).ready(). $(function() {}) is actually just shorthand for $(document).ready() so you are adding code you do not need.
The second is an issue with your logic.
$('#mw_nav .toggle') and $('#m_nav .toggle') click listeners are essentially adding a click listener on the same exact element, but both run different logic. When the $('#mw_nav .toggle') click listener is getting called it checks for a class to exist to decide what class it needs to remove and add. When $('#m_nav .toggle') click listener is getting called it calls a slideToggle function on the current nested <ul> regardless if another menu is opened or closed and there is no check in place of whether or not the rotate_open/rotate_close classes exist allowing for the classes to get swapped. There is no relation between the swapping of rotate_open/rotate_close classes and the logic that slideToggles <ul> up/down.
UPDATE
I have edited your code and made updates that will now work seen here: https://jsfiddle.net/vhfn0q5a/9/
I have added a class of .top_level to the top level items in your HTML. I use this as a way of differentiating the top level <li> from the sub menus. Next, at the end of the click event listener I check to see if the .toggle element clicked is a top level element, if so I target all top level elements that are not the current selected and make sure they have the .rotate_close class.
$(function() {}) shorthand reference

Use this code in your first click handler:
$('#mw_nav .toggle').click(function() {
$(this).toggleClass('rotate_close rotate_open');
if ($('#mw_nav .toggle').not(this).hasClass('rotate_open')) {
$('#mw_nav .toggle').not(this).removeClass('rotate_open').addClass('rotate_close');
}
});
I've updated your FIDDLE with an working example.
Cheers!

Related

jQuery collapsible through toggleClass on element

I have an off canvas navigation menu (classname that is enabled via hover-over using jQuery on my Wordpress site. It is, as it should be, not visible on page load.
For the mobile version, I want the same nav menu to be activated by clicking on a menu icon (that I've given two classes, in this order: mobile-nav-toggle show-nav-mobile). The toggle method seems to only work for a vertical toggle. My solution to replicating the same animation on click rather than hover, is by using the toggleClass method on the icon to toggle between a classname that opens the menu nav (show-nav-mobile) and closes it (hide-nav-mobile) Using the below code:
jQuery(".show-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'0px' }, 250);
});
jQuery(".mobile-nav-toggle").click(function(){
jQuery(".mobile-nav-toggle").toggleClass("show-nav-mobile hide-nav-mobile");
});
jQuery(".hide-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'-640px' }, 250);
});
That doesn't seem to do the job though. The jQuery opens the offcanvasmain div just fine, but doesn't close it again.
What is wrong with my approach?
I assume your element initially looks somewhat like this:
<nav class="mobile-nav-toggle hide-nav-mobile">...</nav>
This means that
a) Both these click handlers will always run when clicking, no matter if the element still has the class hide-nav-mobile:
jQuery(".mobile-nav-toggle").click(function(){
jQuery(".mobile-nav-toggle").toggleClass("show-nav-mobile hide-nav-mobile");
});
jQuery(".hide-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'-640px' }, 250);
});
jQuery finds the element at the moment you define the click handler; it doesn't recheck if the element still has this class when clicking later.
b) This never attaches a click handler:
jQuery(".show-nav-mobile").click(function(){
jQuery(".offcanvasmainnav").animate({left:'0px' }, 250);
});
because at the time of calling jQuery(".show-nav-mobile") it cannot find any element with that class.
To fix it, do this all in a single click handler:
jQuery(".mobile-nav-toggle").on('click', function(){
const that = jQuery(this);
that.toggleClass("show-nav-mobile hide-nav-mobile");
jQuery(".offcanvasmainnav").animate({left: that.hasClass('show-nav-mobile') ? '0px' : '-640px' }, 250);
});

Why is my fadeToggle looping on one certain class?

I am trying to create three clickable divs, one to open, and two to close a popup window. One of the "close" divs works like a charm, however the other loops the fadeToggle. The looping class is .exit (upper left corner, grey box).
Please see JSFiddle; http://jsfiddle.net/StudentEric/zx221ssy/
´$(".maincontainer, .opaquebg").hide();
$("#orange, .exit, .opaquebg").click(function(){
$(".maincontainer, .opaquebg").fadeToggle(500);
});
});´
What have I done wrong?
It is because you are binding the same event for .opaquebg and .exit and .exit is child of .opaquebg. So if you do not stop the #orange click event event, it is going to trigger the event twice just like what you are experiencing right now. Try
e.stopPropagation();
inside of your click event like:
$("#orange, .exit, .opaquebg").click(function(e){
e.stopPropagation();
$(".maincontainer, .opaquebg").fadeToggle(500);
});
Here is your updated fiddle: http://jsfiddle.net/zx221ssy/1/
As a side note, you do not need to fadeToggle your .maincontainer child element since you are already fade toggling your parent .opaquebg. So your code can look like this:
$(function(){
$(".opaquebg").hide();
$("#orange, .exit, .opaquebg").click(function(e){
e.stopPropagation();
$(".opaquebg").fadeToggle(500);
});
});

Once menu item is clicked, close menu and revert the classnames & jquery

Ok... So I have this drop down menu working as I'd like... however I'm trying to figure out how to revert the function back to it's original state after a menu item is clicked.
So first when you trigger the function it does & works great the following:
It swaps out .menu_hide and .lockscreen for .menu_show and .lockscreen_on.
// show and hide mobile menu
$('#triggerMobileMenu').click(function(e) {
e.preventDefault();
// Toggle all 4 classes off or on
$('#mobileMenu').toggleClass('menu_hide menu_show');
$('#mobileScreen').toggleClass('lockscreen_off lockscreen_on');
But now I'm trying to add another piece that says once a menu item is clicked, close the menu and swap the classes back to their original state from .menu_show and .lockscreen_on, to .menu_hide and .lockscreen_off.
$('#mobileMenu ul li a').on('click',function(){
$('#mobileMenu').toggleClass('menu_show menu_hide')({ autoCloseOnClick: true });
$('#mobileScreen').toggleClass('lockscreen_on lockscreen_off')({ autoCloseOnClick: true });
});
});
I should also note that on the same page a scroll to id# may be happening vs just simply taking you to the new url/page. Either case will happen though.
I think that you're making this too complicated. Use the same event handler for both a#triggerMobileMenu and ul#mobileMenu li a since you're having them do the same thing (toggle the visibility of the menu and another element).
$('a#triggerMobileMenu, ul#mobileMenu li a').on('click', function(evt){
evt.preventDefault();
$('#mobileMenu').toggleClass('menu_hide menu_show');
$('#mobileScreen').toggleClass('lockscreen_off lockscreen_on');
});
If you need to know which element was clicked in the event handler, evt.target is available:
if( $(evt.target).is($('a#triggerMobileMenu')) ) {
// do stuff
}
See http://jsfiddle.net/Mph6t/3/
I think it is working as intended. I had to fix some id names that may have been switched in the translation to jsfiddle. Here's a working one as far as I can tell. This leaves the somename2 div still showing. I assume that is going to be blank and just for locking the screen right?
I also changed the link to a new tab for testing purposes. FYI.
Relevant changes are:
$('#somename1 ul li a').on('click',function(){
$('#somename1').toggleClass('menu_show menu_hide')({ autoCloseOnClick: true });
$('#somename2').toggleClass('lockscreen_on lockscreen_off')({ autoCloseOnClick: true });
});

Understanding JQuery. Collapsible menu

I have created a collapsible menu in JQuery with the help of some coding I've found around this site.
And everything work. But now it's time for me to understand how and why it works.
The JQuery:
jQuery(document).ready(function($) {
var submenu = $('.submenu').hide();
$('.open').click(function() {
$this = $(this);
$target = $this.parent().next();
if(!$this.hasClass('close')){
$('.open').removeClass('close');
submenu.slideUp();
$this.addClass('close');
$target.slideDown();
}else{
$target.slideUp();
$this.removeClass('close');
}
});
});
The HTML and CSS are in here: JSFIDDLE!
Can someone break the code down for me, and explain what it does.
I know that it hides my .submenu class when the page loads.
And when I click the class .open the .submenu. slides down
But then I am a bit lost to what it does with my .close class.
Thanks in advance!
No problems :)
Let's start with this:
jQuery(document).ready(function($){});
this wraps around all jQuery code. it defines an anonymous function and attaches it to the event $(document).ready meaning - this code runs only after the entire DOM is loaded. This is needed because if the following code will run before the elements were loaded it will have no effect on them,
var submenu = $('.submenu').hide();
This line picks all elements with class="submenu", hides them - and returns an array of all submenus to the submenu variable. The rest of the explanation will be commented on each line:
$('.open').click(function() { // the following code will run if you click an element with class="open"
$this = $(this); // $this will hold the element you clicked
$target = $this.parent().next(); // $target will hold the next element (relevant single submenu)
if(!$this.hasClass('close')){ // if the current element is open (marked by class="closed")
$('.open').removeClass('close'); // remove the "close" class from all main menu items
submenu.slideUp(); // close all submenus
$this.addClass('close'); // add "close" class only to the clicked main menu item
$target.slideDown(); // open the correct submenu (the element after the clicked main menu item)
}else{ // if current submenu is already open
$target.slideUp(); // close it
$this.removeClass('close'); // remove class "close" from the main menu item.
}
});
When user clicks on a menu group, you need to consider two cases:
The clicked menu group is closed (i.e. it doesn't have the close class)
!$this.hasClass('close')
If so, you first have to close all open menus, and set their class accordingly:
$('.open').removeClass('close');
submenu.slideUp();
Then you can expand the clicked menu group, and mark it as currently open:
$this.addClass('close');
$target.slideDown();
The clicked menu group is already open. The only thing that needs to be done in that case is closing the menu:
$target.slideUp();
$this.removeClass('close');

Change css when tab has active class

I'm trying to change the background colour of the <body> depending on what tab specific is active.
When a tab is active, a class called 'st_view_active' is added onto the tab content. In the tab content I add a hidden div with the hex code of what my body background colour should be when that tab is active, my jQuery code looks like this:
$(document).ready(function() {
$(function(){
$('body').css('backgroundColor',$('.st_view_active').find('.background').text());
});
});
And my html code when the tab is active is following:
<div class="tab-6 st_view st_view_active" >
<div style="display:none" class="background">yellow</div>
<div class="st_view_inner">
tab 6
</div>
</div>
So when tab6 is active the background of the body should be yellow. However, this is not working, the background colour is not changing, what am I doing wrong here?
DEMO and JSfiddle
Thanks
PS: The red and blue square is the next and previous tab handler..
See here: http://jsfiddle.net/CNYDU/25/
I put the default color at the end of sColor, but you could instead grab the first view and use its color. I did it this way to cut down on testing since your fiddle is painful to work with.
$(document).ready(function() {
var hsh = window.location.hash.replace('#','');
var sColor = hsh ? $("#slidetabs_45").find("."+hsh+" .background").text() : "#3b0";
$("body").css("background-color", sColor);
$("#slidetabs_45").slidetabs({
onContentVisible:function(e){
var color = $("#slidetabs_45").find(".st_view_active .background").text();
$("body").css("background-color", color);
}
});
});
I also added the .st_view_active class to the first view so that it will start correctly.
I also added a CSS3 transition to the background color, which isn't necessary.
This sounds like a great opportunity to use data elements in html. Rather than having a hidden div with the background color you want, you can simple add a data-color attribute to your tab a tag. Then when the div is clicked you can set the color easily with an event handler.
link to an updated fiddle - http://jsfiddle.net/CNYDU/15/
Note: The next and previous tabs do not work in this example, but it should be easy to get them working, just attach a listener to each that runs
$('body').css('background-color', $(".st_tab_active").attr('data-color'));
as its callback.
Check out the livequery plugin for jQuery.
Live Query also has the ability to fire a function (callback) when it matches a new element and another function (callback) for when an element is no longer matched. This provides ultimate flexibility and untold use-cases. For example the following code uses a function based Live Query to implement the jQuery hover helper method and remove it when the element is no longer matched.
Their example:
$('li')
.livequery(function(){
// use the helper function hover to bind a mouseover and mouseout event
$(this)
.hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
}, function() {
// unbind the mouseover and mouseout events
$(this)
.unbind('mouseover')
.unbind('mouseout');
});
You should be able to adapt this to your css changes like fired events, and therefor perform your actions based on which tab is active.
I have forked Jlange's jsfiddle, which uses the data attribute, for a demo of how this plugin would be used:
http://jsfiddle.net/nj6ZY/2/
http://jsfiddle.net/nj6ZY/2/show/#tab-10 - Also works with a link to activate a specific tab
And the relevant bits:
$('.st_tabs_ul li a.st_tab_active').livequery(function(){
$('body').css('background-color', $(this).data('color'));
});
Put ID's on your tabs. Example for id="tab6":
$(document).ready(function() {
if ($('#tab6').attr('class') == 'tab-6 st_view st_view_active') {
$('body').css('background-color', 'yellow');
}
});
However, why would you attach this function to document ready only? I would bind the function to when the element is clicked...

Categories