Example HTML (for the sake of clarity):
<nav>
<ul>
<li class="top-navbar-channels">
<div class="dropdown-menu">BLAH, BLAH, BLAH!</div>
</li>
<li class="top-navbar-about">
<div class="dropdown-menu-about">BLAH, BLAH, BLAH!</div>
</li>
<li class="top-navbar-search">
<div class="dropdown-menu-search">BLAH, BLAH, BLAH!</div>
</li>
</ul>
</nav>
Example jQuery code:
jQuery(document).ready(function($){
$('.dropdown-menu').on('show', function () {
$('.top-navbar-channels > a').addClass('selected');
});
$('.dropdown-menu').on('hide', function () {
$('.top-navbar-channels > a').removeClass('selected');
});
$('.dropdown-menu-about').on('show', function () {
$('.top-navbar-about > a').addClass('selected');
});
$('.dropdown-menu-about').on('hide', function () {
$('.top-navbar-about > a').removeClass('selected');
});
$('.dropdown-menu-search').on('show', function () {
$('.top-navbar-search > a').addClass('selected');
});
$('.dropdown-menu-search').on('hide', function () {
$('.top-navbar-search > a').removeClass('selected');
});
});
For those who are curious... the jQuery code adds a new class selected to the active menu item's link. In my case it's Twitter Bootstrap-based collapsible menu, where active means, the menu item is not collapsed i.e. open.
Now, the question is, can the jQuery code be optimized (i.e. same functionality with less code)? If so, how?
Add a common class to common main elements so you can use that single class as the selector. You can also combine the events into one on() call and use toggleClass() on the link. on() allows for multiple space separated events
Example
<div class="dropdown-menu menu_content">
Then for jQuery:
$('.menu_content').on('show hide', function () {
$(this).siblings("a").toggleClass('selected');
});
Perhaps, this code:
jQuery(document).ready(function($){
var $menus = $('.dropdown-menu, .dropdown-menu-search, .dropdown-menu-about');
$menus.on('show', function () {
$(this).siblings("a").addClass('selected'); // or alternatively, $(this).prev("a")
});
$menus.on('hide', function () {
$(this).siblings("a").removeClass('selected'); // idem as above
});
});
This is a little shorter then Matthias... not very much shorter
$(function(){
$('.dropdown-menu, .dropdown-menu-search, .dropdown-menu-about').on('show',function(){
$(this).siblings('a').addClass('selected');
}).on('hide',function(){
$(this).siblings('a').removeClass('selected');
});
});
Related
I was wondering if what can I do with my codes to make it shorter.
Here is my code, it is like a simple tabs.
Btw, this codes are already working, but I'm thinking that if i have many tabs then I have to repeat many click functions.
Is there a way to make my script shorter, Thanks in advance.
$(function () {
$(".invMer, .invEq").hide();
$(".mergers a").click(function () {
$(".invMer").fadeIn();
$(".invEq, .invPe").hide();
});
$(".equity a").click(function () {
$(".invEq").fadeIn();
$(".invMer, .invPe").hide();
});
$(".privateEq a").click(function () {
$(".invPe").fadeIn();
$(".invMer, .invEq").hide();
});
Give all the links the same class, and a data attribute that says which tab it should open. So something like:
<div class="mergers">
<a class="tablink" href="#" data-tab="invMer">Mergers</a>
</div>
And all the tab DIVs should also have a common class:
<div class="tabdiv" id="invMer">
...
</div>
Then you can use a single handler:
$(".tablink").click(function() {
var tab = '#' + $(this).data("tab");
$(".tabdiv").not(tab).hide();
$(tab).show();
});
Use a data attribute
<a data-show=".invPe">
and do
$("a[data-show]").on("click", function () {
var selector = $(this).data("show");
$(".invMer, .invEq, .invPe").hide();
$(selector).fadeIn();
});
Using Bootstrap
<ul class="nav nav-pills nav-stacked col-sm-2 hidden" id="menu">
<li role="presentation" id="LiNewsFeed">News Feed</li>
<li role="presentation" id="LiStatusUpdate">Update Status</li>
<li role="presentation" id="LiWriteWall">Post On Wall</li>
<li role="presentation" id="LiNotifications">Notifications</li>
<li role="presentation" id="LiLogOut">Logout</li>
</ul>
In Javascript, I am disabling some of the <li> like the following:
$('#LiNewsFeed').addClass('disabled');
The Item in the List actually LOOKS disabled, when when I click on it, it actually calls the javascript function, therefore, what I need is to disable the <a href> not just the <li>
I tried adding this after $(document).ready:
$(".nav li.disabled a").click(function () {
return false;
});
But it's not really doing anything.
What I need is to disable the <a href> directly after disabling <li> in my Js code, and not to depend on a click event...
Seems like there is no way to disable an <a href>, so I need a way around it
Any help would be appreciated.
use below code. check working example JSFIDDLE
$(".nav li.disabled a").each(function(){
$(this).attr('href','javascript:void(0);');
});
As you are disabling LI in javascript (runtime), you should use .on to bind events on disabled links:
$(".nav").on('click', 'li.disabled a', function () {
return false;
});
I would check on every link click if the parent has the disabled class.
$('.nav li a').click(function () {
if($(this).parent('li').hasClass('disabled')) {
return false;
}
return true;
});
EDIT, following more info from OP I would suggest the following:
$('.nav li a').each(function() {
var $this = $(this);
// store reference of 'href' attr in case link is re-enabled
$this.data('href', $this.attr('href'));
if ($this.parent('li').hasClass('disabled')) {
// remove href attribute disabling click
$this.removeAttr('href');
} else {
// restore href
$this.attr('href', this.data('href'));
}
});
This code should be run after you add/remove the disabled class on li elements.
EDIT 2 - Rather than you calling functions from the href of <a> links, you could do something like the following:
var events = {
'#LiNewsFeed': 'GetNewsFeed',
'#LiStatusUpdate': 'StatusUpdate'
'#LiWriteWall': 'WriteOnWall',
'#LiNotifications': 'GetNotifications',
'#LiLogOut': 'LogOut'
};
for (var selector in events) {
if (events.hasOwnProperty(selector)) {
try {
$(selector).click(function () {
// assuming function is global
if (typeof window[events[selector]] === 'function') {
// call function
window[events[selector]]();
}
// this is needed if the a element still has a href attr
return false;
});
} catch (e) {
console.log('Invalid Selector');
}
}
}
This way you can control the calling of the function, and check whether it should be called without altering the element, perhaps stick an
if (!$(this).parent('li').hasClass('disabled')) {
...
}
around the function call.
can you convert the a into span?
(code not tested)
$(".nav li.disabled a").replaceWith(function() { return "<span>" + this.innerHTML + "</span>"; });
i have a little problem with my styled Selectfield. I used for this unordered list elemnts (UL / LI) and a H3.
The problem is to close the "Selectfield" by clicking anywhere on the page.
When i bind a click event to the "document", then don't open the SelectField with the current jQuery code.
I have hidden the UL Element by using CSS (display:none).
To open the Select Fields is not the problem. But only without the $(document).bind('click') [...] code.
I hope anyone have a resolution for my.
Thanks.
And here my HTML Code:
<div class="select_container">
<h3 class="reset">Select Items</h3>
<ul class="select_elements">
<li>Select Item 01</li>
<li>Select Item 02</li>
<li>Select Item 03</li>
</ul>
</div>
And here the jQuery Code:
$(document).ready(function(){
var selectFields = {
init: function(){
$('.select_container').on('click',function(){
$(this).find('ul.select_elements').toggle();
$(this).find('ul.select_elements').toggleClass('active');
});
$(document).bind('click',function(){
if( $('.select_elements').is(':visible')){
$('.select_elements.active').hide();
}
else if( $('.select_elements').is(':hidden')){
console.log('visible false ...');
}
});
}
};
$(selectFields.init);
});
You need to use .stopPropagation in $('.select_container').on('click') function to prevent triggiring $(document).on('click')
You need to use toggleClass in $(document).on('click') too
$('.select_container').on('click',function(e){
$(this).find('ul.select_elements').toggle();
$(this).find('ul.select_elements').toggleClass('active');
e.stopPropagation();
});
$(document).on('click',function(){
if( $('.select_elements').is(':visible')){
$('.active').hide();
$('.select_elements').toggleClass('active');
}
else {
console.log('visible false ...');
}
});
FIDDLE
In jquery and javascript an event bubbles up so you have to use e.stopPropagation() on your container click.
check theese pages linki1 or link2 and a possible solution to your problem could be
<script type="text/javascript">
$(document).ready(function(){
var selectFields = {
init: function(){
$(document).bind('click',function(e){
if( !$('ul').hasClass('active')){
$('ul').hide()
$(this).find('ul.select_elements').toggleClass('active');
}
});
$('.select_container').on('click',function(e){
e.stopPropagation()
if( $('ul').hasClass('active')){
$('ul').show()
}else{ $('ul').hide() }
$(this).find('ul.select_elements').toggleClass('active');
});
}
};
$(selectFields.init);
})
</script>
With stopPropagation prevent the event from bubbling and being caught by the document when you click on the list
in some cases you can also use stopImmediatePropagation, for understand differences between stopPropagation and stopImmediatePropagation check this post Post
The only drawback to similar code and to and Batu Zet code, is that If you want the items in the list can be clicked without disappearing, you have to add another stopPropagation on ul tag
Tis is the final Fiddle
I have been trying to change some things with the Flexslider v2 to fit my needs.
I have been trying to use jQuery to target the parent li of the img class="active" because i want to give it a class of selected but I have not been very successful
<ol class="foo">
<li>
<img src="bar.png" class="active"> <-- This class changes img elements depending on the active slide
</li>
<li>
<img src="bar.png">
</li>
<li>
<img src="bar.png">
</li>
</ol>
I came up with something like this:
$(document).ready(function() {
$('.foo li').children().each(function(index, value) {
if($(value).hasClass('active')) {
$(this).parent('li').addClass('selected');
} else {
$(this).parent('li').removeClass('selected');
}
});
});
and it works in the console, but it does nothing within my main.js file.
LIVE DEMO
Simple like one line:
$('.foo li').find('img.active').closest('li').addClass('selected');
Or if you really need it:
LIVE DEMO
$('.foo li').find('img').each(function(index, el) {
if($(el).hasClass('active')) {
$(el).closest('li').addClass('selected');
} else {
$(el).closest('li').removeClass('selected');
}
});
jQuery API Documentation - Closest
Wrap it i document.ready like this in your main.js and then it should work as expected.
You got it worked in console because all elements are loaded when you runt the script.
$(function(){
$('.foo li').children().each(function(index, value) {
if($(value).hasClass('active')) {
$(this).parent('li').addClass('selected');
} else {
$(this).parent('li').removeClass('selected');
}
});
});
Use closest():
$(this).closest('li'),addClass('selected');
Add $(document).ready(function(){
$(document).ready(function(){
$('.foo li').children().each(function(index, value) {
if($(value).hasClass('active')) {
$(this).parent('li').addClass('selected');
} else {
$(this).parent('li').removeClass('selected');
}
});
});
Check the similar question HERE
$('.foo > li').removeClass('selected').each(function() {
if($(this).find('img').hasClass('active')) {
$(this).addClass('selected');
}
});
Why use .each() ? When we can achieve our goal without it.
$(".foo li img.active").parent().addClass("selected");
I have the following code It takes a <ul> and it drops down the contents when clicked. That works great. The problem was that it would also close other menus of the same type when a child <li> was clicked.
I 'fixed' this problem by using the if clause to determine if the item being clicked was also the item that was currently open, but I want to take it a step further and make it so that if the parent ul is clicked again, it will close the menu. I am having a great deal of misunderstanding as to how to approach this. I attempted to stop the propagation of the children elements, but it yields the same results. Can anyone assist?
wiring (document load)
$(document).ready(function () {
$('[data-role="sidebar-dropdown"]').drawer({
open: 'sidebar-dropdown-open',
css: '.sidebar-dropdown-open'
});
});
html
<ul>
<li class=" dropdown" data-role="sidebar-dropdown">
Link Text
<ul class="sub-menu light sidebar-dropdown-menu">
<li><a class="remote" href="pages/...">Link Text</a></li>
<li><a class="remote" href="pages/...">Link Text</a></li>
<li><a class="remote" href="pages/...">Link Text</a></li>
</ul>
</li>
</ul>
JavaScript
(function ($) {
$.fn.drawer = function (options) {
// Create some defaults, extending them with any options that were provided
var settings = $.extend({
open: 'open',
css: '.open'
}, options);
return this.each(function () {
$(this).on('click', function (e) {
// slide up all open dropdown menus
$(settings.css).not($(this)).each(function () {
$(this).removeClass(settings.open);
// retrieve the appropriate menu item
var $menu = $(this).children(".dropdown-menu, .sidebar-dropdown-menu");
// slide down the one clicked on.
$menu.slideUp('fast');
$menu.removeClass('active');
});
// mark this menu as open
$(this).addClass(settings.open);
// retrieve the appropriate menu item
var $menu = $(this).children(".dropdown-menu, .sidebar-dropdown-menu");
// slide down the one clicked on.
$menu.slideDown(100);
$menu.addClass('active');
e.preventDefault();
e.stopPropagation();
}).on("mouseleave", function () {
$(this).children(".dropdown-menu").hide().delay(300);
});
})
};
})(jQuery);
In jQuery events you can read the node which initiated the event by referencing e.target.
if ($(e.target).is("li")) { // do something only if the clicked element was a li }
Regarding closing elements which are not children, instead of doing a global selector $(selector) you should instead do a selector relative to your initiating dom node. It's a common practice to pass this and stashing it inside your jQuery plugin.
return this.each(function(this)) { var $node = $(this); }
Then all lookups would be done like
$node.find(selector).doStuff()