preventDefault on lists that have a link ánd another list - javascript

I have a website where I am not able to change the HTML, I can only inject JavaScript and CSS. The website has a dropdown menu that doesn't work properly on Android. The parent menu is also a link, and when people click it they are taken to the link on the parent instead of opening the child/submenu.
The HTML (simplified)
<ul id="menu">
<li>
Parent menu ▼
<ul>
<li>Submenu link</li>
<li>Submenu link</li>
<li>Submenu link</li>
</ul>
</li>
<li>
Parent menu link
</li>
</ul>
And I have this jQuery:
var topmenuclicked == 0;
$("#menu > li a").click(function(event){
event.preventDefault();
if (topmenuclicked == 0) {
topmenuclicked = 1;
} else {
topmenuclicked = 0;
window.location.href = $(this).attr('href');
}
});
It's a bit messy and not the best way to solve this, but my main problem is with selecting only the a elements that have a submenu.
With the code as it is now I have to click all parent menu links twice and I'm not sure why.
So I need to be able to say something like $("#menu > li:has(ul) a) but I don't believe that works.

Use children("ul").length of li element
$("#menu > li a").click(function(event){
//use $(this).parent().children("ul").length
if($(this).closest("li").children("ul").length) {
event.preventDefault();
// the clicked on <li> has a <ul> as a direct child
}
if (topmenuclicked == 0) {
topmenuclicked = 1;
} else {
topmenuclicked = 0;
window.location.href = $(this).attr('href');
}
});

the previous answer won't work, cause submenu is not inside of A tag, but the rest is good.
Here is how can you fix it:
$('#menu > li a').on('click', function (event) {
if ($(this).next('ul').length) {
event.preventDefault();
// Parent link clicked
} else {
// Nested link clicked
// The ELSE part can be removed if custom logic is not needed
}
});
Another option can be:
$('#menu > li > a').on('click', function (event) {
event.preventDefault();
// Parent link clicked
});
$('#menu > ul a').on('click', function (event) {
// Nested link clicked
});

You can use parents for this. Also, use .on instead of .click
$('#menu').on('click', 'li a', function(event){
event.preventDefault();
var topmenuclicked = 0;
if($(this).parents('ul').length == 1) {
topmenuclicked = 1;
}
console.log('topmenuclicked -> ', topmenuclicked)
// do your stuff here
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul id="menu">
<li>
Parent menu ▼
<ul>
<li>Submenu link</li>
<li>Submenu link</li>
<li>Submenu link</li>
</ul>
</li>
<li>
Parent menu link
</li>
</ul>

put > before a. See below
var topmenuclicked == 0;
$("#menu > li > a").click(function(event){
event.preventDefault();
if (topmenuclicked == 0) {
topmenuclicked = 1;
} else {
topmenuclicked = 0;
window.location.href = $(this).attr('href');
}
});

In part because of #Love-Kesh his solution I came up with this that seems to be working.
$("#menu > li a").click(function(event){
// save parent in variable
var clickedlinkparent = $(this).parent();
// check if parent has any ul element as children
if (clickedlinkparent.children('ul').length) {
// prevent the link from opening
event.preventDefault();
// if link has not been clicked, do nothing
if (topmenuclicked == 0) {
topmenuclicked = 1;
// if link has already been clicked, go to href
} else {
topmenuclicked = 0;
window.location.href = $(this).attr('href');
}
}
});

Related

Active navigation class based on current URL problem

I have the following HTML menu:
<div class="nav">
<ul>
<li class="first">Home</li>
<li>Something</li>
<li>Else</li>
<li class="last">Random</li>
</ul>
<ul style="float:right;">
<li class="first last">News</li>
</ul>
</div>
</div>
And then I have this code:
jQuery(function($){
var current = location.pathname;
$('.nav ul li a').each(function(){
var $this = $(this);
// if the current path is like this link, make it active
if($this.attr('href').indexOf(current) !== -1){
$this.addClass('active');
}
})
})
The code is working great, but it has a problem. For example, if I see the Home page (www.example.com) then all of the menu links receives the active class. Another problem would be that it works great for www.example.com/something but it doesn't keep it active if I go to www.example.com/something/1 etc. Any idea how to fix this? Thanks in advance!
For home page add extra class 'default' in list like.
<li class="first default">Home</li>
jquery code.
jQuery(function($){
var current = location.pathname;
console.log(current);
//remove the active class from list item.
$('.nav ul li a').removeClass('active');
if(current != '/'){
$('.nav ul li a').each(function(){
var $this = $(this);
// if the current path is like this link, make it active
if(current.indexOf($this.attr('href')) !== -1 && $this.attr('href') != '/'){
$this.addClass('active');
}
})
}else{
console.log('home');
$('.default a').addClass('active');
}
})
Use the below jQuery code to add active class:
$(function() {
var pgurl = window.location.href.substr(window.location.href
.lastIndexOf("/") + 1);
$(".nav ul li a").each(function() {
if ($(this).attr("href") == pgurl || $(this).attr("href") == '')
$(this).addClass("active");
})
});
By using indexOf(), you are checking if the link's target is the same the current location.
What you want is not "the same URL" but "the same pattern", so I would tend to use a regular expression :
let re = new RegExp("^" + $(this).attr("href") + ".*");
if (re.test($current)) {
$(this).addClass("active");
}
Note that this would force you to create a separate solution for your link to the main page, else it would always be active.

Disable href link when containing #, but enable all others

So this mostly works, however, the only URL that works is what is specified as "Blog." All the anchor references with # are smooth scrolling on click but all my external links on my page aren't doing anything.
Can I write the prevent default in a way that only includes the href links with "#" in them? I have image links, etc throughout my page and want a simple method to manage it rather than pointing each url out.
<ul class="snip1143">
<li class>Home</li>
<li>About</li>
<li>Work</li>
<li>Blog </li
<li>Contact</li>
<script>
$(document).on('click', 'a', function(event) {
if($(this).data('hover') !== "Blog"){
event.preventDefault();
$('html, body').animate({
scrollTop: $( $.attr(this, 'href') ).offset().top
}, 500);
});
</script>
var doc = document;
var myList = doc.getElementsByClassName("snip1143")[0];
var myListItems = myList.children;
var isHash = false;
var href;
for (var i = 0; i < myListItems.length; i++) {
href = myListItems[i].firstChild.getAttribute('href');
isHash = href.includes("#");
if(!isHash){
myListItems[i].firstChild.addEventListener('click', function(evt) {
event.preventDefault();
});
myListItems[i].classList.add("strike");
}
}
.strike{
text-decoration: line-through;
}
<ul class="snip1143">
<li>Home</li>
<li>About</li>
<li>Work</li>
<li>Blog </li>
<li>Contact</li>
</ul>
Coded directly on SO, I hope I got it right:
$(document).on('click', 'a', function(e) {
if ($(this).attr('href').indexOf('#') !== -1)
e.preventDefault();
};

Removing class on one div when other is clicked

Following is my HTML,
<div class="container">
<ul class="navbar">
<li class="nb-link"><a>Home</a></li>
<li class="dropdown">
<a>CBSE</a>
<ul class="dropdown-menu">
<li>10th Standard</li>
<li>12th Standard</li>
</ul>
</li>
<li class="dropdown">
<a>Engineering</a>
<ul class="dropdown-menu">
<li>JEE - Main</li>
<li>JEE - Advanced</li>
</ul>
</li>
</ul>
I have 2 dropdowns . When I click one, it comes down. But when I click another, even that comes down without closing the previous one . This creates an overlap. The way I'm handling this using JS is as follows
$(document).ready(function() {
$('.dropdown').click(function() {
var $this = $(this);
if ($this.children('.dropdown-menu').hasClass('open')) {
$this.removeClass('active');
$('.navbar').$this.children('.dropdown-menu').removeClass('open');
$this.children('.dropdown-menu').fadeOut("fast");
}
else {
$this.addClass('active');
$this.children('.dropdown-menu').addClass('open');
$this.children('.dropdown-menu').fadeIn("fast");
}
});
});
How can I achieve a functionality using JS such that the previous dropdown closes when I click a new dropdown ? Also, the dropdowns should close when anywhere on the page is clicked ?
can try this
$(document).ready(function() {
$('.dropdown').click(function() {
var $this = $(this);
$('.dropdown').not($this).removeClass('active')
$('.dropdown-menu').not($this.find('.dropdown-menu')).removeClass('open');
$this.toggleClass('active');
$this.find('.dropdown-menu').toggleClass('open');
});
});
Working Demo
this is a function you can use if selectors is not target
// function for if selectors not target
function actionwindowclick(e , selector , action){
if (!$(selector).is(e.target) // if the target of the click isn't the container...
&& $(selector).has(e.target).length === 0) // ... nor a descendant of the container
{
action();
}
}
and you can use it in window click event like this
$(window).on('click', function(e){
actionwindowclick(e , ".dropdown , .dropdown-menu" , function(){
$('.dropdown').removeClass('active')
$('.dropdown-menu').removeClass('open');
});
});
Working Demo
Note: I think you may need to
event.stopPropagation()
while you trying to click on .dropdown-menu itself
$('.dropdown-menu').click(function(e) {
e.stopPropagation()
});
Try:
$(document).ready(function() {
$('.dropdown').click(function() {
var $this = $(this);
$this.children('.dropdown-menu').toggleClass('open');
if ($this.children('.dropdown-menu').hasClass('open')) {
$this.removeClass('active');
$this.children('.dropdown-menu').fadeOut("fast");
}
else {
$this.addClass('active');
$this.children('.dropdown-menu').fadeIn("fast");
}
});
});

How to get index value from parent element?

I have list:
<ul class="nav">
<li>first</li>
<li>second</li>
<li>third</li>
<li>fourth</li>
</ul>
I am trying to get the index of the <li> I just clicked.
What I tried is something with index() but it doesn't work as expected.
Am I missing something?
Here is my code:
console.log($('.nav li').index());
Clicking on the 2nd <li> should return "2" (or 1, if the index is starting with 0)
This here is my click-function:
$('.nav .hasChild > a').click(function(e) {
console.log($('.nav li').index());
....
});
The "hasChild"-class is not important in my case
Try this:
$('.nav .hasChild > a').click(function() {
var indexVal = $(this).closest('li').index();
console.log(indexVal);
});
Try this-
$('.nav .hasChild > a').click(function(e) {
console.log($(this).parent("li").index());//this holds the current element reference which is clicked
}
Perhaps I am missing something with the extra classes but surely it is as simple as;
$('.nav li').click(function() {
console.log($(this).index());
});

onclick outside menu hide submenu using jquery

Here is my code:
$("#menu li:not(:first-child)").click(function () {
$(this).siblings().removeClass('active');
$menu = $(this).find('ul');
$othermenu = $(this).siblings().find('ul');
if($othermenu.is(':visible') == true) {
$othermenu.animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
}
if($menu.is(':visible') == false) {
$(this).addClass('active');
$menu.css({display:'block'}).animate({opacity:'1', easing:'easeOutQuad'}, 500);
} else {
$(this).removeClass('active');
$menu.animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
}
});
using this code to show/hide sub menus on click of menu. I want to change as if i clicked outside menu that time also i want to hide sub menu.
My Html Code like this
<div id="menu" class="showmenubox submenucheck">
<ul> <li><a href="#" >Home</a> </li>
<li>About
<ul ><li>
<strong>aaaa</strong>
bbb
</li>
</ul></li>
<li>Contact
<ul><li>
<strong>aaaa</strong>bbb
</li>
</ul>
</li> </ul> </div>
You want to test whats been clicked when the document is clicked...
$(document).click(function (e) {
var $container = $("#menu");
if (!$container.is(e.target) // if the target of the click isn't the container...
&& $container.has(e.target).length === 0) // nor a descendant of the container
{
$container.find('.active ul').animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
}
});
http://jsfiddle.net/kW2Nb/
Use the code below comments.
$("#menu li:not(:first-child)").click(function (e) {
$(this).siblings().removeClass('active');
$menu = $(this).find('ul');
$othermenu = $(this).siblings().find('ul');
if($othermenu.is(':visible') == true) {
$othermenu.animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
}
if($menu.is(':visible') == false) {
$(this).addClass('active');
$menu.css({display:'block'}).animate({opacity:'1', easing:'easeOutQuad'}, 500);
} else {
$(this).removeClass('active');
$menu.animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
}
/**
* Bind click event on document
* It will hide menu which is currently open and unbind click event on document
*
*/
var me = $(this);
$(document).click(function(e) {
$menu.animate({opacity:'0', easing:'easeOutQuad'}, 500).css({display:'none'});
$(document).unbind("click");
me.removeClass('active');
});
$menu.click(function(e) {
e.stopPropagation();
});
e.stopPropagation();
});

Categories