How to temporarily disable a navigation link using jQuery - javascript

I'm still learning a bit on javascript/jquery and running into a bump. Every post I pull seems to over-complicate the process, unless it really does require all the extra code.
Here's what I'm doing:
Creating a vertical navigation menu with sliding menu's and static sub-menu's
Using HTML (5) layout with DL, DT and DD
Nav menu is using minor CSS for styling
Nav menu is using jQuery (1.8.3)
I have everything working the way I want, but because I'm picky, I want to temporarily disable the link after a menu is expanded. If I try to click the menu that is already expanded, it slides up and then back down. What I wanted to do is make it so it just doesn't react to a click if it's already expanded.
HTML of Nav Menu:
<dl class="nav2">
<dt>Thing1</dt>
<dd>
<ul>
<li>Test Def1</li>
<li>Test Def2<li>
<li>Test Def3</li>
</ul>
</dd>
<dt>Thing2</dt>
<dd>
<ul>
<li>Test Def4</li>
<li>Test Def5<li>
<li>Test Def6</li>
</ul>
</dd>
<dt>Thing3</dt>
<dd>
<ul>
<li>Test Def7</li>
<li>Test Def8<li>
<li>Test Def9</li>
</ul>
</dd>
</dl>
jQuery for Nav Menu:
$(document).ready(function() {
$("dd:not(:first)").hide();
$("dt a").click(function() {
/* was thinking the added code would go here, but I could be wrong */
$("dd:visible").slideUp("fast");
$(this).parent().next().slideDown("fast");
return false;
});
});
I've tried a few things with bind and one, but due to my confusion with writing js/jquery, I'm not finding my trick. Is there anyway possible to say something like:
$(this:active).unbind("click");
or
if ($(this).active(function() {
$(this).unbind("click");
} else {
$(this).bind("click");
)};
I know I'm probably way off, but I'm trying. Is there any way to change this into javascript/jQuery?
When the DT A is clicked -
make THIS DT / DT A not clickable;
When THIS DT / DT A is no longer expanded or visible -
make THIS DT / DT A clickable;
Thanks for the peak. Sorry if this was found somewhere. Each post I've ran into starts expanding this tiny change into several lines of code, whether attacking the CSS, longer then what seems to be needed javascript/jQuery or both. I just really want to try to keep it contained and simple (if at all possible).

You do not want to disable the click (by disabling the anchor, or unbinding the event). You want to not execute an action when the clicked element is currently selected. Do that like this:
$(document).ready(function() {
var active = $("dd:first");
$("dd").not(active).hide();
$("dt a").click(function() {
var dd = $(this).parent().next();
if (! dd.is(active)) {
active.slideUp("fast");
active = dd.slideDown("fast");
}
return false;
});
});

You could add a temporary class to a link which has been clicked, and then remove it once whatever action the event triggered is complete. Test for the class each time a link is click with hasClass, if it does, do nothing, if it doesn't, do something. I have answered a similar question here:
Suppress jQuery event handling temporarily
Here's how it would work with your code (I believe, though may need modification to suit your needs):
$(document).ready(function() {
$("dd:not(:first)").hide();
$("dt a").click(function(e) {
// Prevent link from doing default action
e.preventDefault();
if ($(this).hasClass('fired') == false) {
// Add 'fired' class to disable link
$(this).addClass('fired');
// Do some stuff
$("dd:visible").slideUp("fast");
$(this).parent().next().slideDown("fast");
// Remove 'fired' class to re-enable the link
// You may need to do this in a call back function
// If you are animating something
$(this).removeClass('fired');
}
// Use preventDefault instead of this
/*return false;*/
});
});

Related

jQuery not recognizing click for li item on second page

I'm working to make a couple buttons to change the theme of a website on click. They work on the main page, but when I tried to move them to the second page, they don't work anymore. The click isn't even being recognized at all.
$(document).ready(function(){
$(document).on("click", "#warm", function() {
console.log("Clicked!");
$(b).addClass('color-red');
$(li).addClass('color-red #pages li');
$(h1).addClass('color-red h1');
$('#pages').addClass('color-red #pages');
});}
Here is the html that goes with it
<div class="col-md-4 text-center">
<ul id="colors">
<li id="warm">
Warm
</li>
<li id="cool">
Cool
</li>
</ul>
</div>
The cool function is exactly the same as the warm, except it uses removeClass instead of addClass.
$(document).ready(function(){
$(document).on("click", "#warm", function() {
console.log("Clicked!");
$(b).addClass('color-red');
$(li).addClass('color-red #pages li');
$(h1).addClass('color-red h1');
$('#pages').addClass('color-red #pages');
});}
WOAHHH Back it up partner. First you dont ever want to bind to document, UNLESS you are creating future events. Since you are using the id selector, you should only have 1 of those on the page, which you can rebind if you rebind that particular id to the page. You dont want to blind to the document because it is quite heavy or something. jquery has to parse the entire DOM everytime there is an html change to check if you added another "#warm" (in your example) to see if it needs to create another event binding to that element.
So first off your code should look like this
$(document).ready(function(){
$("#warm").on("click", function(e) {
console.log("Clicked!");
$(b).addClass('color-red');
$(li).addClass('color-red #pages li');
$(h1).addClass('color-red h1');
$('#pages').addClass('color-red #pages');
});}
now time for some clarification, what do you mean you "move them to the second page"? What code in there says you are moving them ? What is the second page?

Showing content based on a nav link clicked

I have a menu selection that looks like this:
<ul class = "menu">
<li>About</li>
<li>Contact</li>
<li>Misc</li>
</ul>
I'm trying to make content associated with each of these links show on click and hide all other content. The JS I'm using looks as follows:
$('.menu li .aboutNav').click(function (e) {
e.preventDefault();
$('.wrapper').hide();
$('.misc').hide();
$('.contact').hide();
$('.about').show();});
I want to have a function like this for each menu element, but currently it isn't working for all the elements in the menu. I've looked at other threads with the same problem I'm having but none of them seem to directly apply to the way I'm doing it.
I just started learning html, js, css so I could be going about this the wrong way and that's why the other threads haven't really helped.
EDIT: Here's a pastebin of all of my HTML http://pastebin.com/FjcNXGkY
A more efficient way would be to add the same class to all links and another class to all content items...
HTML:
<ul class="menu">
<li>About</li>
<li>Contact</li>
<li>Misc</li>
</ul>
<div class="menu-content about">About</div>
<div class="menu-content contact">Contact</div>
<div class="menu-content misc">Misc</div>
JavaScript:
var $content = $('.menu-content');
function showContent(type) {
// this assumes that you really must select
// the content using a class and not an ID (which you've
// referenced in the href)
$content.hide().filter('.' + type).show();
}
$('.menu').on('click', '.menu-btn', function(e) {
// get the type to pass to showContent by grabbing
// the hash from the anchor href and removing the first
// character (the #)
showContent(e.currentTarget.hash.slice(1));
e.preventDefault();
});
// show 'about' content only on page load (if you want)
showContent('about');
Demo on jsbin: http://jsbin.com/hagonesuwo/edit?html,js,output
------------------------------------- EDIT -------------------------------------
I have just seen your edit with a link to your pastebin. If there is only one content item for each nav item then you can use IDs instead...
HTML:
<ul class="menu">
<li>About</li>
<li>Contact</li>
<li>Misc</li>
</ul>
<div id="about" class="menu-content">About</div>
<div id="contact" class="menu-content">Contact</div>
<div id="misc" class="menu-content">Misc</div>
JavaScript:
var $content = $('.menu-content');
function showContent(selector) {
$content.hide();
$(selector).show();
}
$('.menu').on('click', '.menu-btn', function(e) {
showContent(e.currentTarget.hash);
e.preventDefault();
});
// show '#about' content only on page load (if you want)
showContent('#about');
This would be much better as it would mean the navigation would still jump to the relevant content if JS was disabled or failed to download for any reason.
This solution assumes that the a elements will only have a single class.
$('.menu li a').click(function (e) {
e.preventDefault();
$(".wrapper,.misc,.content,.about").hide(); // Hide all.
$("." + this.className.slice(0,-3)).show(); // Show one based on the class
});
It binds the same handler to all the a elements.
When clicked, it hides all the targeted elements, and then slices away the "Nav" from the .className to create a selector to choose the one to display.
Not sure what .wrapper does, since it's not in your HTML.
You have a couple of problems with your JS:
you select items by class .misc instead of ID #misc
the way you coded the click is very rigid. Make it more elastic like:
$('.menu').on('click', 'li', function (e) {
$('article').hide();
var id = $(this).find('a').attr('href'); // $(this) is the clicked LI
$(id).show();
})
I assume all items with IDs #about, #contact etc. are simply article HTML elements and I hide them all before showing the right one. Hope this helps.
EDIT
Or even a bit more elegant hiding the other contents:
$('.menu').on('click', 'li', function (e) {
var id = $(this).find('a').attr('href');
$(id).show().siblings().hide();
})
$(".menu").children().click(function(){
$(".menu").children(function(){
$("."+$(this).attr("class").replace("Nav","")).hide();
})
$("."+$(this).attr("class").replace("Nav","")).show();
})
This would be a universal solution, considering that you can have any menu item with class "someItemNav"; if it's clicked any items are hidden and only "someItem" is shown.

document.click to remove class on page not behaving properly

I'm trying to create a global style of dropdowns which toggle between open and closed when their menu icon is clicked, but also close whenever anywhere else on the page is clicked. The way in which I'm opening or closing this dropdowns is by adding or removing a class called "open" to the parent of the dropdown.
The idea of that (to be more clear) is that the normal class of the dropdown has display: none; set on it, but if it's a descendant of something with the class "open", then it has display: block;
So, without further ado, here's what I have so far:
"openable" is a class of 'parent' elements which can be clicked on to add the "open" class.
<script>
$(document).ready(function(){
$('.openable').click(function(){
if($(this).hasClass("open")){
$(this).removeClass("open");
}
else{
$(this).addClass("open");
}
});
});
On it's own that actually works fine - it acts as a decent enough toggle for the dropdowns. Of course, clicking anywhere else won't close the dropdowns.
My apparently non-functioning close script is:
<script>
$(document).ready(function(){
$(document).click(function(event) {
var clicked = $(event.target);
if(clicked.hasClass(".open")){
}
else{
if($(".open").length > 0){
$(".open").each(function(){
$(this).removeClass("open");
});
}
}
});
});
</script>
With that script on the page, dropdowns cease to work altogether, and console isn't throwing up any errors for me to work off of.
Any better way of doing this?
Thanks
edit: html markup is something like
<li class="navItem dropdown openable">
<span><img src="img/settings.png"></span>
<ul class="subNav hubDrop">
<li>Nav item 1</li>
<li>Nav item 2</li>
<li>Nav item 3</li>
<li>Nav item 4</li>
</ul>
</li>
for each one. the li tag there is within another ul (remember, this is for dropdown menu essentially)
jsFiddle Demo - Since you haven't provided any HTML I mocked up some elements...
Update: You don't specify if more than one element can be 'open' at once; in your current solution they can be, so I kept that behavior. However, to limit it to one being open you can add $('.open').not(this).removeClass('open'); inside the .openable click handler.
Part One: Why not just use .toggleClass
$(document).ready( function() {
$('.openable').click( function() {
$(this).toggleClass("open");
});
});
Part Two: No need for a second ready handler; in the first, add this:
$(document).click( function(e) {
var clicked = $(e.target).closest('.openable');
if ( clicked.length == 0 ) {
$(".open").removeClass('open');
}
});
jsBin demo
just played around a bit (don't know your markup.)
<div>
<h2 class="openable">ICON 1</h2>
<div class="cont"></div>
</div>
$('.openable').next('.cont').hide();
$('.openable').click(function(e) {
e.stopPropagation();
$('.opened').removeClass('opened');
var d = $(this).next('.cont');
var visib = (d.is(':visible')) ?
/*yes*/ d.slideUp() :
/*no */ ($('.cont').slideUp()) (d.slideDown().prev('.openable').addClass('opened')) ;
});
$(document).click(function(){
$('.cont:visible').slideUp().prev('.openable').removeClass('opened');
});
I don't believe you can just do $(document).click(), it's not wrong but you never click the document itself, you click children of.
I have a very similar menu system and I capture an event this way:
$('.navTab').mouseover(function (event) { navEvent($(this), event.type); });
Then remove all "open" and reapply "open" to the selected item.
I believe you don't want to capture all document click events. jQuery Event.target
How about making everything but the openable classed elements execute your click method?
var openable = $(".openable");
$("div, h2").not(openable).click(function(){
$('.cont').slideUp().prev('.openable').removeClass('opened');
});

jquery - sub menu is hidden on mouseout of main menu

This seems like a pretty easy one, but I couldn't solve my issue by reading the related questions here on SO.. so here's mine. I have:
<ul class="main-menu">
<li>Letters</li>
<li>Numbers</li>
</ul>
<ul class="sub-menu hidden">
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
I want .sub-menu to appear on mouseover of .main-menu, and keep visible while the mouse is over both .main and sub.
$(".main-menu, .sub-menu").hover(
function(){
$('.sub-menu').hide().removeClass('hidden').slideDown('fast');
}, function(){
$('.sub-menu').slideUp('fast');
}
);
But mouseout is fired when I mouseout of main-menu, even though I mouseout of it into sub-menu, so the sub-menu is hidden.
Any suggestions? Restructuring the HTML is not an option, though.
The following assumes you have a second sub-menu to go with the "Numbers" main-menu item, something like I've shown here: http://jsfiddle.net/aY7wW/ - and further assumes that when you said "Restructuring the HTML is not an option" you meant that I couldn't even suggest adding attributes to associate each sub-menu with its main-menu item. To work within this restriction I've used the main-menu li element index to relate to the sub-menu ul element index (obviously this works only if the sub-menus are defined in the same order as the corresponding main-menu items). If you could add some id attributes or something it would simplify the code somewhat, but anyway:
var timerId,
$mainMenuItems = $(".main-menu li"),
$subMenus = $(".sub-menu");
$mainMenuItems.hover(
function(){
clearTimeout(timerId);
$subMenus.slideUp('fast');
$($subMenus[$mainMenuItems.index(this)]).hide()
.removeClass('hidden')
.slideDown('fast');
}, function(){
var i = $mainMenuItems.index(this);
timerId = setTimeout(function(){$($subMenus[i]).slideUp('fast');},500);
}
);
$subMenus.hover(
function() {
clearTimeout(timerId);
},
function() {
$(this).slideUp('fast');
}
);
The basic idea is to use setTimeout() to delay hiding the sub-menu on mouseout from the main-menu. This gives you time to move the mouse over the sub-menu, and if you do the timeout is cleared so it won't be hidden. Then when you move the mouse off the sub-menu it is hidden. But allowing for movement of the mouse just between the different main-menu items, on initial hover we also clear any outstanding timeout and hide previously shown sub-menus so that only the correct sub-menu will show. I've used a delay of 500ms, but obviously you can set that to whatever feels natural for you.
Working demo: http://jsfiddle.net/aY7wW/
Try putting both the main and sub menus in a div, and put the hover event on the div.
How about something like:
$(".main-menu").mouseover(function () {
$('.sub-menu').slideDown('fast').click(function (){
$(this).slideUp('fast');
});
});

Set back again the current menu link to "active" once navigation through menu stops

Ok, maybe you can't understand much from the title, so I'll try to explain it a bit more in here.
Basically I have a navigation, like this:
<ul class="primaryNav">
<li class="nav1">About us</li>
<li class="nav2">Our world</li>
<li class="nav3">Active page</li>
</ul>
Now I'm on the "Active page" page and the "Active menu link" is active as you can see (the class is set manually by me on each page).
The user can navigate through that other menus (hover them) and they become active, and my "Active menu link" inactive and so on. (through jQuery)
Well, what I'm trying to do, is, once the user stops navigating through my menu, and move mouse cursor outside the navigation container (let's say), set back to "active" the "Active menu link" wich was initially active, with some timeout, maybe.
Hope I was clear enough about what I'm trying to achieve.
Thanks,
Adrian
Something like:
var resetMenu = function() {
$('li.active').attr('class','active').siblings().attr('class','inactive');
};
var to;
$('ul').bind('mouseout', function() {
window.clearTimeout(to);
to = window.setTimeout(resetMenu, 1000);
});
I'm using attr() instead of add/remove classnames here based on your example. You can alter the 1000 for more/less time to wait before "resetting" the menu.
I'm not completely clear what you want to do, but it sounds like you're looking for the jQuery hover() event, which fires when the mouse enters the matched element, and the callback function when it leaves.
$('ul.primaryNav').hover(function() {
// do stuff when the mouse enters the <ul>
},
function() {
// do stuff when the mouse leaves the <ul>
});
I suspect you might be intending to use <ul id="primaryNav"> and <li id="Nav1">, etc.—ids instead of classes to uniquely identify these elements.
What exactly // do stuff means depends on what exactly you're looking for, but probably just adding and removing an active class will do instead of using an inactive class as well.
I'm not looking for just the .hover() event from jQuery, it's little more than that.
I am already using jQuery .hover() event to add to the current hovered link the class "active" and to the others the class "inactive".
But in the Active page the "active" class from is set manually by me, and I want that to be active again when users stop navigation through my menu. I mean, when I play with the menu and hover the links it does the stuff I told you about (add class active to current, add class inactive to others) - when I mouseout the navigation area I want that the "active" class to "go" back again to the initial link who had that className when I first arrived into that page.
I have some submenus, also, wich are shown on hover, but I guess that's not so relevant for my question.
This should work. If you need explanations just comment on answer
var as;
var ul = $('ul.primaryNav').mouseout(function() {
toogle(
as.filter('.active'),
as.filter(function() {
return $(this).data('originalActive') === true;
})
);
});
as = ul.find('a');
//remember which one was original active
as.filter('.active').data('originalActive', true);
function toogle(ina, act) {
ina.removeClass('active').addClass('inactive');
act.removeClass('inactive').addClass('active');
};
as.mouseover(function() {
//make current active, inactive others
toogle(as.filter('.active'), $(this));
});

Categories