Jquery - manipulating classes in a simple dropdown menu - javascript

All,
I previously posted a question but didnt get an answer (admittedly due to poor wording). Am re-posting after updating/ testing the code a bit more.
I want to build a simple drop down menu. Jsfiddle.
PROBLEM:
The menu drops down & upon reclicking the tab, folds away nicely. However, when the menu is down & another tab is clicks, things go pear shaped, i.e. the other menu does not drop down.
Ive tested the jquery code extensively using firebug & have noticed a lot of abnormalities. E.g. I thought for my purpose, the jquery code:
$('ul', curTab).*** would be the same as $(curTab).children(0).***, sometimes this code runs fine, other times it doesn't.
Consistently Ive noticed the 'addClass' & 'removeClass' method not adding & removing the class as intended.
The if ($('.cTabActive')){...} doesn't work, syntax error?
If I do if ($('.cTabActive', aFileTabs)){...}, this doesn't work either...
Im totally at my wit's end with this supposedly simple code. Help would be greatly appreciated.
Code:
(Please review the jsfiddle.net code above)
HTML:
<div id="filemenu"> <!-- right tabs menu -->
<ul id="fm_ul">
<li class="filetabs">File
<ul class='cDropDownItems'>
<li class="m_items"><span class="aHeading">New</span><span class="shortcutK">Ctrl-U</span></li>
<li class="m_items"><span class="aHeading">Open</span><span class="shortcutK">Ctrl-Z</span></li>
</ul></li><li class="filetabs">Edit
<ul class='cDropDownItems'>
<li class="m_items"><span class="aHeading">Undo</span><span class="shortcutK">Ctrl-M</span></li>
</ul></li><li class="filetabs cLastFileTabs">Settings
<ul class='cDropDownItems'>
<li class="m_items m_itemsCK" id="frontView"><img src="Img/tickB&W1.png" alt="tick" /><div class="filler"></div><span class="aHeading">Front View</span><span class="shortcutK">Ctrl-A</span></li>
</ul></li>
</ul>
</div> <!-- close -> 'filemenu' div -->
</div> <!-- close -> 'menu_bars' div -->
JAVASCRIPT:
$('.filetabs').on('click', function (e) {
function abc() {
if ($(curTab).hasClass ('cLastFileTabs')) {
$('ul', curTab).css ({left: '-66.6%'});
$('ul',curTab).animate ({opacity: 1}, 125, 'linear');
} else {
$('ul', curTab).css ({left: 0});
$('ul', curTab).animate ({opacity: 1}, 125, 'linear');
} }
var aFileTabs = $('.filetabs');
var curTab = $(this);
if ($('.cTabActive')) {
var prevDropDown = $('.cTabActive').parent();
var prevDDChild = $(prevDropDown).children(0);
$(prevDDChild).removeClass('cTabActive').addClass('cPrevTabActive'); }
if ($('ul',aFileTabs).hasClass('cPrevTabActive')) {
$('.cPrevTabActive',aFileTabs).animate ({opacity: 0}, 500, 'linear', function () {
$('ul', aFileTabs).css ({left: '9999px'});
$('ul', aFileTabs).removeClass ('cPrevTabActive'); }); }
if ($(prevDropDown).get(0) !== $(curTab).get(0)) {
$(curTab).children(0).addClass ('cTabActive');
abc();
} else {
return;
} });

Kayote,
Here is a working sample. I added .length(), redid the If logic, and use the setTimeout function so fade-in and fade-out does not conflict.
DemoGood Luck!

Related

Hide siblings when another dropdown is opened

I'm fairly new to .js and have been working on a dropdown nav menu. I've got most of it functioning, but I was asked to include a specific snippet for the menu activation.
I'd like to figure out how to make the other subnav items hide or scroll up when a different subnav is opened.
What am I doing wrong here?
<div id="nav_mob">
<div id="nav-toggle"><span></span></div>
<div class="dropdown_mob">
<ul>
<a class="dropdown_btn">
<li>Overview</li>
</a>
<div class="subnav_mob">
<ul>
<li>Introduction</li>
<li>Research</li>
<li class="padded">Planning & Preparation</li>
<li>International</li>
</ul>
</div>
<a class="dropdown_btn"><li>Profile</li></a>
<div class="subnav_mob">
<ul>
<li>My Account</li>
<li>My Cart</li>
<li>Check Out</li>
<li>Log Out</li>
</ul>
</div>
<a class="dropdown_btn"><li>Search</li></a>
<div class="subnav_mob">
<ul>
<li><div id="smallsearch"><input type="text"></div></li>
</ul>
</div>
</div>
</ul>
</div>
</div>
the snippet I was given:
var dropdown = document.getElementsByClassName('dropdown_btn');
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener('click', function() {
this.classList.toggle('active');
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display == 'block') {
dropdownContent.style.display = 'none';
} else {
dropdownContent.style.display = 'block';
}
});
}
and the fix I tried to implement:
$(document).ready(function() {
$('.dropdown_btn').on('click', function() {
var state = $('.dropdown_btn').is('.active');
if(state) {
$('.dropdown_btn').removeClass('active').next('.subnav_mob')
.slideUp();
} else {
$('.dropdown_btn').addClass('active').next('.subnav_mob').slideDown();
$.closest('.dropdown_btn').siblings('.dropdown_btn')
.find('.dropdown_mob').slideUp().end();
$.find('.dropdown_btn').not(this).removeClass('active');
}
})
})
Your first problem is that $('dropdown_button') selects every element with that same class, not just the one you clicked on. Operating on it will thus operate on every dropdown at once. You may have noticed that clicking one button causes every dropdown to open, and clicking another button causes them all to close again. This is why.
Your second problem is that $.closest is not a thing. If you press F12 and check out the console, you'll notice an error being thrown from that line, saying that '$.closest' is not a function. It's actually 'undefined', and attempting to invoke it as a function with () causes this error. This prevents any code after this point from being run, though even if you fix this that code still won't work for similar reasons. $.find is not a function, either, for example. closest and find, like next and slideup, are methods on jQuery instances, not on the global jQuery object itself.
This should work. Note that $(this) refers to the clicked element wrapped in a JQuery instance:
$(document).ready(function() {
$('.dropdown_btn').on('click', function() {
var state = $(this).is('active');
if(state) {
$(this).removeClass('active')
.next('.subnav_mob').slideUp();
} else {
$(this).addClass('active')
.next('.subnav_mob').slideDown();
$(this).siblings('.dropdown_btn').removeClass('active')
.next('.subnav_mob').slideUp();
}
})
})
I would recommend stepping through each call in this, compare it with the jQuery documentation, to really make sure you understand it. I'd also might recommend trying to do it without jQuery-- using the native DOM API like the original snippet was doing. Such an exercise might be frustrating, but valuable.

Trying to do a:active to stay on untill other link is clicked

What I'm trying to do is this: I have two links hot/update. When hot is clicked it should turn red and update to be black. When update is clicked it should turn red and hot to be black.
This works on a Fiddle, but not on my website.
I was able to find various answers on SO, as this seems like a common thing to ask. I was implementing one by one, but none of them works. They seem to work fine in fiddle but not on my web.
HTML:
<div id="Space" >
<ul>
<li role="presentation" class="sort">
<a class="link" href="/?sort=score&page=1" style="text-decoration:none;">hot</a>
</li>
<li role="presentation" class="date">
<a class="link" href="/?sort=date&page=1" style="text-decoration:none;">update</a>
</li>
</ul>
</div>
JavaScript:
$(function() {
var links = $('a.link').click(function() {
links.removeClass('active');
$(this).addClass('active');
});
});
CSS:
a.link.active { color: red; }
a, a:visited { color: black }
Right now, this does what a:active does, it won't stay red.
var links = does not do what you think it does.
You are thinking it is doing this:
var links = $('a.link');
But, since you're assigning it to the actual click event, it's not resulting in that selector.
You need to revise your code as follows:
// This is a "safer" document ready, to prevent conflicts with other $ libraries
jQuery(function($) {
$('a.link').click(function() {
// Remove the class from all other links
$('a.link').removeClass('active');
// Add the class to _just this link_
$(this).addClass('active');
});
});
Or, a version that preserves the var links:
// This is a "safer" document ready, to prevent conflicts with other $ libraries
jQuery(function($) {
// Assign all links to the "links" variable
var links = $('a.link');
links.click(function() {
// Remove the class from all other links
links.removeClass('active');
// Add the class to _just this link_
$(this).addClass('active');
});
});
Here's a working fiddle: https://jsfiddle.net/cale_b/tqzt8f7s/1/
So to clarify you want certain buttons to be highlighted based on whether or not the url has a certain query. Highlight sort if url contains /?sort=score&page=1 and highlight date if url contains /?sort=date&page=1.
To do this all you need to do is search for each of those strings inside of your page's (window.location.search). The code for such a thing would be.
const highLightWhat = (window.location.search).search('sort=score') !== -1 ? 'Highlight sort' :
(window.location.search).search('sort=date') !== -1 ? 'Highlight date' :
'Highlight Nothing';
This flag then can be used as a reference to highlight one 'a' tag or another.
I hope this helped! (:
Try this javaScript once
$(function() {
$('a.link').click(function(event) {
event.preventDefault();
$('a.link').removeClass('active');
$(this).addClass('active');
});
});

jQuery class change not triggered in IE? Chrome/FF work as designed

I've got a little jQuery script that should display a fixed nav menu once the page is scrolled below a 200px threshold and then change the class on each menu list item to "current" once that section hits the top of the viewport.
The problem is the class change piece isn't working in IE (tested in IE11). IE console isn't throwing any errors and it works as designed in Chrome/FF.
The fadeIn/hide function works flawlessly across the board. I've got another piece of script to switch out some content based on a click event and that's working across the board as well.
I've looked at some other questions with answers revolving around blur/focus in IE, but my comprehension level just isn't there yet.
It probably doesn't matter, but I have jQuery 1.11 hosted locally.
Am I overlooking something obvious or is this more involved? Any help is so genuinely appreciated!
Rough working version of the site is at www.4sdesignstudio.com/new-projects/bwh/index.html.
Quick, abridged version of the HTML:
<footer class="main-links">
<ul>
<li>Welcome</li>
<li>The Tasting Room</li>
<li>Tasting Menu<li>
<li>Upcoming Events<li>
<li>The Artwork<li>
<li>Current Wine Releases<li>
<li>Wine Club<li>
<li>Contact Us<li>
</ul>
</footer>
<section id="main" class="marker">
A bunch of content
</section>
<section id="main2" class="marker">
A bunch of content
</section>
<section id="main3" class="marker">
A bunch of content
</section>
<!-- ...etc, etc -->
The jQuery script:
<script>
$(document).ready(function(){
// Cached variables to avoid multiple jQuery calls
var $mainLinks = $('.main-links');
var $headerLogo = $('.header-logo');
var $mainTastingMenu = $('#main-tasting-menu');
var $dessertTastingMenu = $('#dessert-tasting-menu');
var $menuSwitch_1 = $('#menu-switch1');
var $menuSwitch_2 = $('#menu-switch2');
// Plugins
$('.lightbox').nivoLightbox();
$('.scroll-pane').jScrollPane();
$('.scroll-pane2').jScrollPane();
// Event handlers
$menuSwitch_1.on('click', function(event) {
$mainTastingMenu.toggle('show');
$dessertTastingMenu.toggle('hide');
});
$menuSwitch_2.on('click', function(event) {
$mainTastingMenu.toggle('hide');
$dessertTastingMenu.toggle('show');
});
$(window).on('scroll', function(event) {
if ($(this).scrollTop() > 200) {
$mainLinks.fadeIn();
$headerLogo.fadeIn();
} else {
$mainLinks.hide();
$headerLogo.hide();
}
var top = $(this).scrollTop(),
idx = $('section.marker').sort(function (a, b) {
return top - $(b).offset().top;
}).first().index('section.marker'),
el = $('.main-links li a').eq(idx);
if (!el.hasClass('current')) {
$('.main-links li a').removeClass('current');
el.addClass('current');
}
});
});</script>
The problematic code is right here:
var top = $(this).scrollTop(),
idx = $('section.marker').sort(function (a, b) {
return top - $(b).offset().top;
}).first().index('section.marker'),
el = $('.main-links li a').eq(idx);
If you debug this in IE you will never get an index other than 0.
Even after playing with this for a while I couldn't quite understand your logic - so I decided to work up my own approach to determining the currently displayed div:
http://jsfiddle.net/6mkh2xme/3/
This has been tested on IE (windows, some ancient version), as well as Chrome and FF on a Mac.

How to animate element move up after removing previous elements?

So I have this sample code:
<ul>
<li class="class1">row1</li>
<li class="removeme">row2</li>
<li class="removeme">row3</li>
<li class="removeme">row4</li>
<li class="class1">row5</li>
</ul>
//Javascript
$('.removeme').remove();
How do I make the row5 element animate its movement up once all the removeme elements are removed? My css3 transitions are also set.
You could put the "remove me" li's in a container (like a span) and collapse that container.
$(container).fadeTo(200,0).animate({height: 0});
Something like that.
I am not sure about what you have set in css3, but below is what you can do with jQuery.
$('.removeme').animate({height: 0}, 2000, function () {
$(this).remove();
});
DEMO: http://jsfiddle.net/MwYH5/
If you want it removed one by one, then you can chain like below.
DEMO: http://jsfiddle.net/MwYH5/1/
(function removeNext(jq) {
jq.eq(0).animate({height: 0}, 1000, function () {
$(this).remove();
(jq = jq.slice(1)).length && removeNext(jq);
});
})($('.removeme'))
Ref: http://paulirish.com/2008/sequentially-chain-your-callbacks-in-jquery-two-ways/#comment-24910

Activate Current Content Part in jQuery UI Accordion Menu

I'm trying to figure out how to dynamically activate the correct content part of a jQuery UI Accordion menu depending on the page currently being viewed. I've searched extensively and it seems like others have had issues with this in the past, but I haven't yet found a solution that works for me. I know that active can be set to open a certain index of the menu, but I need to do this dynamically.
I'm thinking that I can achieve what I want using the activate method, I just can't seem to figure it out. I'd like to stay away from setting cookies as that usually won't work with back/forward buttons and direct navigation via a specific url. Anyone have any ideas? Thanks in advance!
Here is the simplified structure of my menu:
<div id="menu">
<div id="sections">
<div class="grouping accordion">
<a id="heading1" href="#">Heading #1</a>
<div class="sub-items">
Item #1
<br />
Item #2
</div>
</div>
<div class="grouping accordion">
<a id="heading2" href="#">Heading #2</a>
<div class="sub-items">
Item #4
<br />
Item #6
</div>
</div>
</div>
</div>
And here is my jQuery Accordion init:
$('#sections').accordion({
header: '> .accordion > a',
autoHeight: false,
collapsible: true,
active: false,
animated: 'slide'
});
So if you are currently on the /item4 page for example, the group under Heading #2 should be expanded.
EDIT:
I found what seems to be a pretty good solution and posted that as an answer below, hopefully this will help someone with a similar problem!
To activate a specific tab, you'll want to use the accordion('activate', index) method. Example:
$( "#sections" ).accordion('activate', 2);
However, you will need something that defines an index key per page. You can probably even generate this dynamically. I would probably create a Pages object:
Pages = {
"heading1" : {
"id": 1,
"is_active": false,
"items": {
"item1": {
"href": "item1",
"name": "Item #1"
},
"item2": {
"href": "item2",
"name": "Item #2"
}
}
},
"heading2" : {
/* etc*/
},
}
With some hackish jQuery magic, you can loop through your headings
var active_heading_index = null;
$.each(Pages, function(heading) {
$.each(heading.items, function(item) {
if($(location).attr('href') == item.href) {
heading.is_active = true;
// or
active_heading_index = heading.id
}
});
});
if(active_heading_index) $( "#sections" ).accordion('activate', active_heading_index);
Anyhow, I'm sure there are cleaner and more efficient ways of doing it.
While working on some CSS for the active headings on the menu I stumbled on a pretty clean and easy solution. Looks like I might have been overthinking things!
Using the same HTML as in the question, here's the JavaScript that is working for me:
//accordion menu
$('#sections').accordion({
header: '> .accordion > a',
autoHeight: false,
collapsible: true,
active: '.selected',
animated: 'slide'
});
//add currentPage class to current menu item based on url
var url = window.location.href;
url = url.substr(url.lastIndexOf("/") + 1);
$("#sections").find("a[href='" + url + "']").addClass("currentPage");
//get id of header anchor tag
var headerId = $(".currentPage").parents(".accordion").children("a").attr("id");
//check if headerId is set, if so activate that id
if (headerId) {
$('#sections').accordion('option', 'animated', false);
$('#sections').accordion('activate', $('#' + headerId));
$('#sections').accordion('option', 'animated', 'slide');
}
This solution is pretty simple, it gets the current page from the url and compares it against each link in the accordion menu. If it finds a match, it gives that link a class of currentPage (which allows us to then style that link accordingly via css). Then it looks for a parent of that link with a class of .accordion, finds the first child link (the accordion header) and grabs the header's id. Assuming a header id has been found, we can then use the activate method to expand the correct section.
If you are going back to the server for every page click (standard non Ajaxy way), the server can add a "selected" class to the proper node. So you'd get back something like this at the client (I'm only writing the essential code, skipping most of the labels).
<ul id="menu">
<li>
<ul>
<li>
</li>
<li class="selected">
Menu 102
</li>
<ul>
</li>
<li>
...
</li>
<ul>
Then simply find the proper index to give to the activate property of the accordion.
$(document).ready(function() {
var index = $("li.selected").parents("li").last().index();
$("#menu").accordion({
active: index,
collapsible: true
});
});
The parents("li").last() jQuery returns the top most element. This only works if you only have one sub element with the class "selected", which should be the case for your menu.
I did it using this code:
var newsNum = parseInt(window.location.hash.slice(1));
$(document).ready(function(){
$("#menu").accordion('activate', newsNum );
});
And the url looks like example.com/index.html#1

Categories

Resources