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
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.
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();
};
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");
}
});
});
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());
});
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();
});