Show Hidden Sub-Menu OnClick By Avoiding Link Of Parent Menu - javascript

I am working on a project where the most bad thing is that I can't edit HTML code of my project. I can only edit CSS/JavaScript. My project is that I have a list of menu using <ul><li>... having sub-list also in it. The full HTML code is giving below...
<ul class="main_list">
<li class="parent">
Menu-1
<ul class="children">
<li>SubMenu-1</li>
<li>SubMenu-2</li>
<li>SubMenu-3</li>
</ul>
</li>
<li>Menu-2</li>
<li>Menu-3</li>
<li>Menu-4</li>
<li class="parent">
Menu-5
<ul class="children">
<li>SubMenu-1</li>
<li>SubMenu-2</li>
<li>SubMenu-3</li>
</ul>
</li>
</ul>
This is the HTML code that I can not edit. I can only edit or add CSS/JavaScript. Here I want to hide all children menus and will show on click of there parent menu. But when we click on there parent menu then it goes to the external link that is on parent menu. So is there any way or solution for this...???
Update:
Keep in mind that I also want the parent menu link working too. I have an idea to add some text in front to parent menu like show/hide and make some JavaScript to open its children menu and in this case parent menu link will also work if we will click on it directly. Now can we add some text/icon in front of parent menu using JavaScript as I can't edit HTML?

Your click-function:
$('.main_list .parent > a').on('click', function(event){
event.preventDefault();
var href = $(this).attr('href'); // save the href for further use
$(this).siblings('.children').show(); //or whatever show-function you want to use
window.location.href = href; //if you want to user to be redirected
//OR
window.open(href,'_blank'); //for opening a new tab
});
For your second request, you can do somethin like that:
$(document).ready(function{
$('.main_list .parent').prepend('<span class="show">Show</span>');
});
then your selector in the click-handler above would be:
$('.show')
Demo

Cach your parent click event via JavaScript, then use event.preventDefault() to stop redirecting, then u can make some logic to show/hide menu items.
$(document).ready(function(){
$.each('.parent', function(){
$(this).prepend('<div class="clickableBox"></div>');
})
$(document).on('click', '.clickableBox', function(event){
//show/hide logic here
})
})

Based off of my comment above...
Append a drop down arrow next to the menu item for items with children - clicks on the parent item would navigate to it's link but clicks on the arrow would open up the submenu
JSfiddle DEMO
CSS:
ul.children {
display: none;
}
JQUERY:
$(function(){
$('li.parent').each(function(){
$(this).children('a').after('<img src="http://upload.wikimedia.org/wikipedia/commons/f/f7/Arrow-down-navmenu.png" />');
});
$('li.parent img').on("click",function(){
$(this).siblings('ul.children').toggle();
});
});
EDITED JQUERY (with arrow image toggle):
$('li.parent img').on("click",function(){
if($(this).hasClass('open')) {
$(this).removeClass('open');
$(this).attr('src','Arrow-down.png');
} else {
$(this).addClass('open');
$(this).attr('src','Arrow-up.png');
}
$(this).siblings('ul.children').toggle();
});
Updated DEMO

Since I can't see the full HTML, I'm acting like main_list is the only one.
// Get all anchors in menu
var anchors = document.getElementsByClassName('main_list')[0].getElementsByTagName('a');
// Change HREF to do nothing
for(a in anchors){
a.href = "javascript:void(0);
}
// Do other stuff
Make that code run at the end of the page after everything has loaded. Changing the href to javascript:void(0) will make there be no action.

The below works for me :)
jQuery(function( $ ){
$(document).ready(function(){
$('.main_list a').click(function (e) {
if ($(this).parent().children('ul').is(':visible') != true) {
$(this).parent().children('ul').show();
e.preventDefault();
return false;
}
})
});
});

Related

jQuery toggle: Close all open li when another one is clicked

I've got an accordion menu which toggles on click.
This is the code :
$('ul.internal-nav-list li ').on('click', function () {
$(this).find('.internal-sub-list li ').toggle();
});
And the markup looks like this:
<div id="internal-nav">
<ul class="internal-nav-list">
<li><a>products</a>
<ul class="internal-sub-list">
<li>product1</li>
<li><a href="product2.aspx" >product2</a></li>
<li>product3</li>
</ul>
</li>
</ul>
</div>
Now I'm trying to enable that when an li element from the menu is open and the user clicks on another li, the open one will automatically close. Can anybody give me a suggestion on how to do this?
I'v I'm interpreting what you want correctly, try this:
var mainlis = $('.internal.nav.list > li'); // cache selector
mainlis.on('click', function(e) {
e.preventDefault();
var me = $(this);
mainlis.hide();
me.show();
});
The other existing answers come close, but it seems like what you want to do is hide the children of other menu items when the main menu items are clicked. If that is the case, the following will do:
$('.internal-nav-list > li > a').on('click', function () {
var $thisLi = $(this).parents('li');
$thisLi.siblings().find('.internal-sub-list').hide();
$thisLi.find('.internal-sub-list').show();
});
Note the first selector: this restricts the click handler to just the anchor, not the entire li. That means if they click on a child of the currently displayed main menu item, the function will not be called. That way you don't risk having a flicker as the click the submenu items...
In the handler itself, it traverses back to the parent li, finds its siblings and hides their children. Then is shows the submenu for the currently selected main menu.
Note that I took the liberty of hiding the entire ul of the non-selected menus; this should be faster than hiding each child. Perhaps not significantly, but I find it's best practice to perform these kinds of actions on the container rather than all children of the container.
The simplest solution is to close all lielements and open only the one clicked
$('ul.internal-nav-list > li').on('click', function () {
$(this).siblings('li').slideUp();
$(this).slideDown();
});
EDIT As Morfie pointed out, only the immediate children li of the internal-nav-list should be clickable, thus the > operator is used.
Thanks for the suggestions- I got it working this way in the end (in case it helps anyone)
$('ul.internal-nav-list li').on('click', function () {
$close = $(this).find('.internal-sub-list li ').toggle();
$('.internal-sub-list li').not($close).hide()
});

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');
});

add/remove class with jQuery on link select

I'm trying to write a function in jQuery that will add a class to a selected link (which opens a page in an iframe) then remove that class when another link is selected. I received some help from another member here before for a similar type of thing, but that involved radio buttons and tables.
I tried playing with it for awhile, but jQuery is still pretty new to me so I don't know a whole lot about it.
Basically, I have about 3-4 groups of links contained in <div id="CollapsiblePanelContent"> ... </div> and I would like to add a style to the <a> tag within this container that the user selected.
Any help would be greatly appreciated. Thank you.
<div id="CollapsiblePanelContent">
Link1
Link2
Link3
Link4
</div>
<script type='text/javascript'>
$(function() {
$('div').click(function(event) {
$(this).closest('.CollapsiblePanelContent').addClass('selected').parent().siblings().each(function() {
$(this).find('.CollapsiblePanelContent').removeClass('selected');
});
});
});
</script>
$('#CollapsiblePanelContent a').on('click', function(e){
e.preventDefault(); // prevent page reload, you may remove it if don't need
$(this).addClass('selected').siblings().removeClass('selected');
});
As CollapsiblePanelContent is id so correct selector will be #CollapsiblePanelContent not .CollapsiblePanelContent.
But if you use CollapsiblePanelContent for multiple divs then instead of id it should be class with selector .CollapsiblePanelContent. Because multiple elements can have same id.
You can try :
function handlelink(this)
{
$(this).siblings().removeClass('selected');
$(this).addClass('selected');
//do the rest with the click
}
Based on the HTML you've provided the following should work:
$(function() {
$('.CollapsiblePanelContent a').click(function() {
$(this).addClass('selected').siblings().removeClass('selected');
});
});
That binds the click event handler to any <a> elements inside <div class="CollapsiblePanelContent">, which adds the selected class to the clicked link, and removes the same class from all of its siblings.

Clickable LI overrules links within the LI

I have a LI with some information, including some links. I would like jQuery to make the LI clickable, but also remain the links in the LI.
The Clickable part works. I just need the links within to work as well.
NOTE: They work if you right click and choose "Open in new tab".
HTML
<ul id="onskeliste">
<li url="http://www.dr.dk">Some info with links Imerco</a>
</ul>
jQuery
$(document).ready(function() {
$("#onskeliste li").click(
function()
{
window.location = $(this).attr("url");
return false;
});
})(jQuery);
I've found a simular question here, but it doesn't seem to solve my problem.
jQuery DIV click, with anchors
Can you help me?? :-)
Thank you in advance...
Use the event target, like:
$("#onskeliste li").bind('click', function(e){
switch(e.target.nodeName){
case 'LI':{
e.preventDefault();
e.stopPropagation();
window.location = $(e.target).attr('url');
break;
}
case 'A':{
// do something
break;
}
}
});
The problem your having is caused by event propagation.
The click on the <a/> tag bubbles up to the <li/> tag, therefore causing the li's click event to "overrule" the link's click.
Essentially, the li's click happens immediately after the clicking on the link. It's like you've clicked on a link to one site, and then clicked a link to a different site before the browser had a chance to change the page.
A solution to this would be to stop the event from bubbling up to the <li/>, thus preventing it from changing the window's location.
I suggest using event.stopPropagation() on the <a/> tag, like this:
$('#onskeliste li a').click(function(e) {
e.stopPropagation();
});
Can you just change the mark up to this and not write js for this?
<ul id="onskeliste">
<li>
Some info with links
Imerco</a>
</li>
</ul>
As #GeReV said, it's event propagation.
$(document).ready(function() {
$('#onskeliste li').click(function(e) {
if ($(e.target).is(':not(a)')) {
window.location = $(this).attr('url');
return false;
}
});
})(jQuery);
This looks at what you clicked and if it's not a link it looks at the url attribute on the list element. If it is a link it does its normal link thing.

Categories