Removing and adding Classes on Dropdown Menus on Hover - javascript

I have a Navigation built that have drop down menus,
HTML STRUCTURE LIKE SO
<li class="c-header__subnav-item c-header__subnav-item-is-hidden c-header__subnav-item-is-visible-md">
<a class="c-header__subnav-links u-caps js-c-header__subnav-trigger" href="#">
Action Review Review
<i class="fa fa-angle-down fa-lg c-btn__icon-right-sm"></i>
</a>
<ul class="c-header__subnav-dd">
<li class="c-header__subnav-dd-item">
<a class="c-header__subnav-links c-header__subnav-links--dd" href="#">
Overview
</a>
</li>
<li class="c-header__subnav-dd-item">
<a class="c-header__subnav-links c-header__subnav-links--dd" href="#">
Review Form
</a>
</li>
<li class="c-header__subnav-dd-item">
<a class="c-header__subnav-links c-header__subnav-links--dd" href="#">
Performance Card
</a>
</li>
<li class="c-header__subnav-dd-item">
<a class="c-header__subnav-links c-header__subnav-links--dd" href="#">
Recent Recordings
</a>
</li>
</ul>
</li>
When You Hover On the a.js-c-header__subnav-trigger
It addes a class to its self as well as its sibling ul ( the dropdown menu)
This is perfect but since the hover is triggered on the 'a' element If I toggle the class when and I go to hover on the drop down menu it gets removed before I can because of hovering off the 'a' element.
If I just add the classes and do not use toggle how would I remove both classes once I hover off the A element or Dropdown menu.
What needs to be achieved is
1.) If main nav link is hovered add an active class to itself and drop down is triggered and can be seen. If you hover out WITHOUT engaging the dropdown both active and dropdown class are removed
2.) If main nav link is hovered add an active class to itself and if dropdown IS engaged by user keep both classes until dropdown is hovered out of or 'A' Element.
CURRENT JQUERY CODE
;(function($, window, document, undefined) {
var $win = $(window);
var $doc = $(document);
var $classes = {
SubNavTrigger : 'js-c-header__subnav-trigger',
SubNavItemActive : 'c-header__subnav-item-is-active',
SubNavDropDown : 'c-header__subnav-dd',
SubNavDropDownActive : 'c-header__subnav-dd-is-active'
};
var _isMobile = false;
_isMobile = ($win.width() <= 1024) ? true : false;
// Check if user is on touch on page load
// if isMobile use click events
// if not mobile use hover events
if(_isMobile) {
$("." + $classes.SubNavTrigger).on('click', function(){
if ( $(this).hasClass( $classes.SubNavItemActive ) ){
// If Item has active class removeClass
$(this).removeClass( $classes.SubNavItemActive )
} else {
// If Item does not have active class addClass
$(this).addClass($classes.SubNavItemActive);
} //End if
// Add Active Class To Subnav.
$(this).siblings().toggleClass($classes.SubNavDropDownActive);
});
} else {
$("." + $classes.SubNavTrigger).on('hover', function(){
$(this).addClass($classes.SubNavItemActive);
// Add Active Class To Subnav.
// If set to toggle impossible to hover on this menu.
$(this).siblings().addClass($classes.SubNavDropDownActive);
});
}
})(jQuery, window, document);
Thanks In Advance for any help.
Live Site Link to see
http://100dc.vincebrown.me/integrity-pledge

So I would make a few changes, I would move the s-c-header__subnav-triggerclass to the parent li. I would then change the jquery to use the hover(in,out). The in function would look something like
function () {
$(this).addClass($classes.SubNavItemActive);
// Add Active Class To Subnav.
$(this).children().addClass($classes.SubNavDropDownActive);
}
and the out
function () {
$(this).removeClass($classes.SubNavItemActive);
// Add Active Class To Subnav.
$(this).children().removeClass($classes.SubNavDropDownActive);
}
Here is a jsfiddle

Related

Clicking outside of an element to hide it, doesn't work with multiple elements

I want to hide multiple navigation bars when clicked outside of it, it makes sense to do so, But only one of them hides for one obvious reason.
HTML:
<nav class="navigation">
<ul>
<li><b>Aken</b></li>
<li class="right dropdown">
<a href="#" class="navigation-link nav-trigger">
Akar Muhamad
<img class="profile-picture" src="http://placehold.it/30x30/3498db/333">
<i class="fa fa-caret-down" aria-hidden="true" style="position: relative; right: 3%;"></i>
</a>
<div class="dropdown-content">
Profile
Settings
Logout
</div>
</li>
<li class="right dropdown">
<a href="#" class="navigation-link nav-trigger">
Akar Muhamad
<img class="profile-picture" src="http://placehold.it/30x30/3498db/333">
<i class="fa fa-caret-down" aria-hidden="true" style="position: relative; right: 3%;"></i>
</a>
<div class="dropdown-content">
Profile
Settings
Logout
</div>
</li>
</ul>
</nav>
JS:
$('.nav-trigger').on('click', function() {
// Loop through all the drop-downs, and make all of them invisible
// Except the one we clicked on.
$(this).siblings('.dropdown-content').toggleClass('visible');
var that = this;
$('.dropdown').each(function() {
if (that != this) {
$(this).siblings('.dropdown-content').removeClass('visible');
}
});
});
// TODO: Fix a bug where it doesn't work on multiple navigation bars.
$(document).on('click', function(event) {
if(event.target !== $('.nav-trigger')[0]) {
$('.dropdown').each(function() {
$(this).find('.dropdown-content').removeClass('visible');
});
}
});
Now, as you can see, I passed 0 as an index to check. But what I want is to loop through all of them and use the index as the key to that. Whenever I do that, it doesn't work at all, It also disables the click to show the navigation content function too.
Here's the JSBin.
You actually don't have to use loops here and you don't need to know the index.
$('.nav-trigger').on('click', function() {
// remove visible class from each .dropdown-content:
$('.dropdown-content').removeClass('visible');
// add visible class to .dropdown-content next to the clicked .nav-trigger:
$(this).siblings('.dropdown-content').addClass('visible');
});
$(document).on('click', function(event) {
// check if the clicked element is .nav-trigger:
$(event.target).is('.nav-trigger') ||
// if not, remove visible class from each .dropdown-content:
$('.dropdown-content').removeClass('visible');
});
JSFiddle Demo
Remove the loops and simply hide all of the dropdowns. Then add back the one you care about if necessary.
This code stores the dropdown visibility at click and uses it to toggle the visibility after hiding the dropdown content. This means that clicking the header will both open and close the dropdown.
$('.nav-trigger').on('click', function(event) {
// store current dropdown state
var visible = $(this).siblings('.dropdown-content').hasClass('visible');
// hide all dropdowns
$('.dropdown .dropdown-content').removeClass('visible');
// if we were visible, hide, and vice-versa
$(this).siblings('.dropdown-content').toggleClass('visible', !visible);
// prevent document handler from being fired
event.stopPropagation();
});
// hide all dropdowns if click propagates to document
$(document).on('click', function(event) {
$('.dropdown .dropdown-content').removeClass('visible');
});
JSBin

active class is removed when page refreshes jQuery

I have a UL on my page which is acting as navigation. In my footer I have some jQuery code so when I click the link it removes the active class on the li and then places it on the current li that has been clicked. This works as I click however when the page reloads the active class goes back onto the previous li.
Here is my code
jQuery(document).ready(function () {
"use strict";
// Init Demo JS
Demo.init();
// Init Theme Core
Core.init();
$('.sidebar-menu > li').click(function (e) {
$(".active").removeClass("active");
$(this).addClass("active");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav sidebar-menu">
<li class="sidebar-label pt20">Menu</li>
<li class="active">
<a href="/dashboard">
<span class="glyphicon glyphicon-home"></span>
<span class="sidebar-title">Dashboard</span>
</a>
</li>
<li>
<a href="/fixtures">
<span class="fa fa-calendar"></span>
<span class="sidebar-title">Fixtures</span>
</a>
</li>
<li>
<a href="/players">
<span class="glyphicon glyphicon-book"></span>
<span class="sidebar-title">Players</span>
</a>
</li>
</ul>
Am I missing something in my jQuery to keep the class on the desired li?
Your JS is losing context with the refresh.
What you can do is run another function on load to check which url you're on, and set active state based on that. Something like this:
var setDefaultActive = function() {
var path = window.location.pathname;
var element = $(".sidebar-menu a[href='" + path + "']");
element.addClass("active");
}
setDefaultActive()
My solution is based on this link.
I needed nav pills to remain active after page refresh.
You can probably format this to fit your needs.
$(document).ready(function () {
// On page load
$('a[data-toggle="pill"]').on('show.bs.tab', function (e) {
// Get the id for the pill that was last shown and set it to local storage
localStorage.setItem('activeLink', $(e.currentTarget).attr('id'));
});
// After page loaded
// Get the id for the pill from local storage
var activeLink = localStorage.getItem('activeLink');
// If it's there, click it
if (activeLink) {
$(`#${activeLink}`).click();
}
});

Toggle section visibility based on data-attributes and class

I have a menu which will be used to toggle different sections of the page. Each list item in the menu has a data-attribute. This data-attribute matches with the class of the section i would like to toggle.
How can I match the data-attribute of the active menu item with the class of the section I would like to toggle in the main content?
Any help appreciated!
Codepen
link
Markup:
App Menu
<ul class="tablet--nav__Parent">
<li data-name="js-classifieds--description" class="active">
<i class="icon-description"></i>
Description</li>
<li data-name="js-classifieds-specification" class="">
<i class="icon-specification"></i>
Specification
</li>
<li data-name="js-classifieds-reviews" class="">
<i class="icon-userreviews"></i>
User Reviews</li>
<li data-name="classifieds--valuation" class="">
<i class="icon-roadtests"></i>
Road Tests & Reviews
</li>
Main Content
<main class="main-content" role="main-content">
<div class="js-classifieds--description active">
<section class="advert-description">
<p>Asteroid Grey</p>
</section>
</div>
<div class="js-classifieds-specification">
<div>
<p>Room Beige</p>
</div>
</div>
<div class="js-classifieds-reviews">
<div>
<p>Random Review</p>
</div>
</div>
I can toggle the active class on the menu and based of off that class, I would like to show my relevant section. I would then check if the data attribute of the active menu item matches the class of the item I would like to toggle and this is the bit that I am struggling with.
I have the follwing JS
var toggleStates = function() {
//Find all li[s] in .tablet--nav
var $tabletnavLi = $(".tablet--nav__Parent").find("li");
//Loop through them and take car of active class on current item
$($tabletnavLi).each(function() {
var $self = $(this);
$self.click(function() {
//Add active class to active tab
$self.addClass("active");
var activeElement = ($(".active").data().name);
//Remove from siblings - other elements on page
$self.siblings().removeClass("active");
});
});
};
Ideally I would be able to do something like:
$('.main-content > div').find(activeElement).addClass('active
section').siblings().removeClass('active-section');
Unfortunately, this does not work.
I did't see where you call toggleStates function. Well this below code should do the trick, try it out :
// hide for all section
$('.main-content > div').removeClass('active').hide();
// current click on a tag
$('.tablet--nav__Parent a').click(function () {
// remove class for all li element
$('.tablet--nav__Parent li').removeClass('active');
// cache parent element
var current = $(this).closest('li');
// get data attributes values from li element
var dataName = current.data('name');
// add active class to currenct click li element
current.addClass('active');
// remove class active from all section , and hide them
$('.main-content > div').removeClass('active').hide();
// add class to MATCHED section and show it
$('.'+dataName).addClass('active').show();
});
i hide all the sections for initial state, demo purposed. You can change it for what section should displayed first.
DEMO

Removing active state when toggling between divs

I have created multiple top down menu items. When the links are clicked a div slides down to show some content.
What I am trying to do with these links is toggle between them. When one div is opened an active state is added to the link, when it is closed the active state is removed and the div hidden. When you click between the links I have managed to get them to toggle between each other and the active state is added to the div that is opened.
What I cannot achieve is removing the active state and resetting some css.
Here is my Javascript:
//menu toggle
$(".trigger").click(function() {
var divToToggle = $( $(this).data('target') );
$(".toggle:visible").not(divToToggle).hide();
$(".trigger").not(divToToggle).removeClass('active');
$('.top-nav').css('margin-top', '20px');
divToToggle.slideToggle("fast", "linear");
$(this).toggleClass('active');
$('.top-nav').css('margin-top', '0px');
return false;
});
The .toggle class is on all the divs that are toggled:
<div class="account-container toggle hide"></div>
<div class="collections-container toggle hide"></div>
<div class="search-container toggle hide"></div>
The .trigger class is on all my links:
<ul class="top-nav">
<li><a class="hidden-tablet" href="">home </a></li>
<li><a class="hidden-tablet" href="">about us </a></li>
<li><a class="hidden-tablet" href="">where to buy </a></li>
<li><a class="hidden-tablet" href="">contact us </a></li>
<li class="tablet-menu visible-tablet"><a class="tablet-menu trigger" href="" data-target=".tablet-menu-container">tablet menu</a></li>
<li class="account"><a class="account trigger" href="" data-target=".account-container">account</a></li>
<li class="collection"><a class="collection trigger" href="" data-target=".collections-container">collections</a></li>
<li class="search"><a class="search trigger" href="" data-target=".search-container">search</a></li>
<li class="basket"><a class="basket trigger" href="" data-target=".home-basket-container">basket</a></li>
</ul>
It's hard to say where exactly your code is going wrong, but I've re-written it so it works slightly differently. Your click handler has to handle two possibilities: either we're clicking to hide an existing section, or we're clicking to switch to a new section. But we can also think of this as being two steps, with the second one optional: either we hide an existing section, or we hide an existing section and show a new one.
I've also switched to using ev.preventDefault() to stop the link from firing, named the jQuery variables so they start with $ (which makes them easier to differentiate). You can try it out on jsfiddle here.
$(document).ready(function () {
$(".trigger").click(function (ev) {
ev.preventDefault();
var $clickedLink = $(this);
var $divToToggle = $($(this).data('target'));
var isHideOnly = $clickedLink.hasClass('active');
// Hide the existing div and remove 'active' class.
$(".toggle:visible").hide();
$(".trigger").removeClass('active');
$('.top-nav').css('margin-top', '20px');
// If we're showing a new one, reveal it and set the active class on the link.
if (!isHideOnly) {
$divToToggle.slideToggle("fast", "linear");
$('.top-nav').css('margin-top', '0');
$clickedLink.addClass('active');
}
});
});

Adding a class to an element which is not selected/focused

I have a button, when it is hovered i want to add a CSS class to another element. However i have multiple elements and only want to add it to a specific one.
Currently i have :
$("ul.subnav").parent().append("<span></span>"); //Only shows drop down trigger when js is enabled (Adds empty span tag after ul.subnav*)
var button = $('#loginButton');
button.hover(function (login) {
$("ul.navbar-nav li span").addClass("subhover");
}, function () { //On Hover Out
$("ul.navbar-nav li span").removeClass("subhover"); //On hover out, remove class "subhover"
});
This works, however it adds the class to all the elements.
<li>
<a id="loginButton">
<img class="IconStyle" src="Icons/loginIcon.ico"></img>
</a>
<ul class="subnav">
<li>
</li>
<li>
</li>
</ul>
<span class=""></span> // This is the element i want to add a class to.
The is what i would like to add the class to, however as i said there are 5 of these created programmatically
You could use toggleClass and in/out hover handler:
button.hover(function (login) {
$(this).closest('li').find('span').toggleClass("subhover");
});
Change your HTML to:
<li>
<a id="loginButton">
<img class="IconStyle" src="Icons/loginIcon.ico"></img>
</a>
<ul class="subnav">
<li>
</li>
<li>
</li>
</ul>
<span id = 'spanElement'></span>
and your JQuery to:
var button = $('#loginButton');
alert($("ul.navbar-nav li span").eq(1000000));
button.hover(function (login) {
$("#spanElement").addClass("subhover");
}, function () { //On Hover Out
$("#spanElement").removeClass("subhover"); //On hover out, remove class "subhover"
});

Categories

Resources