Loop through DOM elements with JQuery to assign a click handler - javascript

I need to loop through the DOM with JQuery, and add a click handler to multiple parent elements that contain a child that will also be given a slideToggle(). I have the logic working fine when I add the click handlers manually, but now I need to be able to dynamically do this to multiple parent elements.
Here is my HTML:
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>
Basically, you click on .sub-menu-link to slideToggle() .sub-menu-list.
Here is the JS that I have working so far. It targets the id's manually currently, which feels gross:
$('#sub-menu-link-1').click(function() {
$('#sub-menu-list-1').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
$('#sub-menu-link-2').click(function() {
$('#sub-menu-list-2').slideToggle(100);
$(this).toggleClass('active-menu-link');
});
My apologies if this is something very apparent to do in JQuery. I am not at all familiar with it, and it just so happens to be a requirement of this project.

you could simply use below code.
select all list items with class name and add listener. click will be attached to all elements
$('.sub-menu-link').click(function() {
$(this).slideToggle(100);
$(this).toggleClass('active-menu-link');
});

You already have classes, so just use them instead of the ids: use this to refer to the clicked element, .next() to get the next sibling (the li.sub-menu), and .find('.sub-menu-list') to get to the ul you want to toggle:
$('.sub-menu-link').click(function() {
const $subMenuList = $(this).next().find('.sub-menu-list');
console.log($subMenuList.text().trim());
$subMenuList.slideToggle(100);
$(this).toggleClass('active-menu-link');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="map-poi-nav">
<ul class="map-poi-nav-dropdown">
//Parent #1
<li class="sub-menu-link" id="sub-menu-link-1">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Activities
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-1">
<li><a><span>•</span>Golden State Park</a></li>
<li><a><span>•</span>Sunrise Oaks City Park</a></li>
</ul>
</li>
</ul>
<ul class="map-poi-nav-dropdown">
//Parent #2
<li class="sub-menu-link" id="sub-menu-link-2">
<a href="#">
<img src="https://svgshare.com/i/ADc.svg"> Dining
</a>
</li>
<li class="sub-menu">
<ul class="sub-menu-list" id="sub-menu-list-2">
<li><a><span>•</span>The Loft Grill</a></li>
<li><a><span>•</span>Fish Grill & Bar</a></li>
</ul>
</li>
</ul>
</div>

You can use jQuery's .next() like so:
$(".sub-menu-link").click(function() {
$(this).next(".sub-menu-link").slideToggle(100);
$(this).toggleClass("active-menu-link");
})
Or you can chain them and use ES6 arrow syntax to make it more concise:
$(".sub-menu-link").click(() => $(this).toggleClass("active-menu-link").next(".sub-menu-link").slideToggle(100));

You should try this if your list and link ids have similiar pattern as in the code you have shown
$('#sub-menu-link').click(function() {
var id = $(this).attr("id").replace("sub-menu-link", "")
$('#sub-menu-list-'+ id).slideToggle(100);
$(this).toggleClass('active-menu-link');
});

Related

Close dropdown upon clicking another

I a working on a to make a reponsive dropdown navigation bar with vanilla JavaScript. In mobile view I want that upon click one dropdown the another should close. JavaScript here:
dropbtns.forEach(link => {
link.addEventListener("click", function(e) {
e.currentTarget.nextElementSibling.classList.toggle("showdd");
});
});
and show dropdown:
.showdd {
height: auto;
}
html code:
<div class="nav-container">
<div class="brand">
Logo
</div>
<nav>
<div class="nav-mobile"><a id="nav-toggle" href="#!"><span></span></a></div>
<ul id="nav-list">
<li>
Home
</li>
<li>
About
</li>
<li class="dropdown">
</i>
<ul class="nav-dropdown">
<li>
Web Design
</li>
<li>
Web Development
</li>
<li>
Graphic Design
</li>
</ul>
</li>
<li>
Pricing
</li>
<li class="dropdown">
</i>
<ul class="nav-dropdown">
<li>
Web Design
</li>
<li>
Web Development
</li>
<li>
Graphic Design
</li>
</ul>
</li>
<li>
Contact
</li>
</ul>
</nav>
</div>
full code can be find here.
So, if you want to collapse all other .nav-dropdown when one is being clicked on, you simply will need to:
Store the reference of the .nav-dropdown of the current element (for comparison later)
Toggle its class (as you're doing already)
Go through all other .nav-dropdown in your DOM tree and iterate through them. If they do not match the current reference, then you know the dropdown belongs to another link and you can remove the class
With that in mind we arrive at the code below:
dropbtns.forEach(link => {
link.addEventListener('click', e => {
const ownDropdown = e.currentTarget.nextElementSibling;
ownDropdown.classList.toggle('showdd');
document.querySelectorAll('.dropbtn + .nav-dropdown').forEach(el => {
if (el !== ownDropdown)
el.classList.remove('showdd');
});
});
});
It works on your Codepen after I edit the following line.
links.forEach(link => {
link.addEventListener("click", function(e) {
links.forEach(link => {
link.nextElementSibling.classList.remove("showdd"); // Here
});
e.currentTarget.nextElementSibling.classList.toggle("show");
});
});
By the way, what is "showdd"?

getting last item in an each() loop

I'm struggling to understand how to get the last item in an each() loop. I asked a question last week on this topic, which can be seen here: .find() relationship with loops, each() and this keyword - .find() returning 4 when it should only be 2
The original requirement was to check a series of uls inside uls, and if there were more than 1 lists I need to add a class. Now - I need to build upon this code where if there are more than three lists inside a div, or it is the last ul in a series, I need to add a class to the last ul as well.
I did research on the topic and will be referencing this answer: Last element in .each() set
For reference, the first sample case is below:
$(function(e) {
var getMenuItems = $(".item");
getMenuItems.each(function( index ) {
if ($(this).find("ul.sub-menu").length > 0) {
$(this).addClass("red");
}
});
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
</ul>
This code just checks if there are more than 1 lists inside a div and if there are add a class.
Now the next step is to not only add a class to the divs with more than 1 list but the last ul in the series irregardless of amount of lists. The answer Last element in .each() set suggests to simply cross reference index and see if you are at the last item.
The highest upvoted answer says to:
Check index against the length of the set and you're good to go:
That concept integrated into my sample looks like this:
$(function(e) {
var getMenuItems = $(".item");
var howManyListItems = getMenuItems.length;
getMenuItems.each(function( index ) {
if ($(this).find("ul.sub-menu").length > 0) {
$(this).addClass("red");
} else if (index == (howManyListItems.length - 1)) {
console.log($(this));
$(this).addClass("red");
}
});
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
</ul>
The expected/desired behavior is to add the red to the last item but sadly that does not happen.
As can be seen as a troubleshooting measure, console logging this into that conditional returns nothing. So is that not the last item of the array? How would you modify it/target it? What does that conditional represent? Since console logging does nothing, how does one go about troubleshooting this code?
How do you hit the last element in an each loop and modify it's DOM properties?
This is as easy as:
$(function(e) {
$(".sub-menu:last-of-type").last().addClass("red");
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
</ul>

Need an element's parent index using jquery or javascript

I have three <ul>s that expand when their buttons are clicked. Not all three <ul>s will show up - only when there is a notification to show. I hard-coded the values for now, but I can instantiate them on an as-needed basis.
Right now, they cover each other when they expand. I would like the others to move when a list is expanded so they don't cover each other. I was thinking of getting the index of the one whose button is clicked and then resetting the bottom style of the others. I need to get the index of the <ul> parent of the button that was clicked, probably using jQuery but straight JavaScript is fine as well. Can anyone help?
Here is my code:
<div id="NotificationDiv">
<ul id="noticeLead" class="notification_base notification_Lead"><button id="notification_button">Lead Notice</button>
<div>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #1</a>
</li>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #2</a>
</li>
</div>
</ul>
<ul id="noticeTask" class="notification_base notification_Task"><button id="notification_button">Task Notice</button>
<div>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #5</a>
</li>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #6</a>
</li>
<div>
</ul>
<ul id="noticePolicy" class="notification_base notification_Policy"><button id="notification_button">Policy Notice</button>
<div>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #3</a>
</li>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #4</a>
</li>
</div>
</ul>
</div>
And in the $(document).ready, I have:
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
});
Try this:
var myParentId; //Here you'll store the id of the clicked element
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
myParentId = $(this).attr("id");
});
Thank you everyone for your input. I changed my structure to a table assigning .parent class to the header row and .child class to the data row and put this code in the jQuery ready function and it works great.
function getChildren($row) {
var children = [];
while($row.next().hasClass('child')) {
children.push($row.next());
$row = $row.next();
}
return children;
}
$('.parent').on('click', function() {
var children = getChildren($(this));
$.each(children, function() {
$(this).toggle();
})
});

how to add javascript function to a class of active?

how to add javascript function to a class of active ??
I do not understand completely about javascript.
if i click menu its like remove and add new class nav active.
<div id="sidebar">
<ul id="mainNav">
<li id="navDashboard" class="nav active">
<span class="icon-home"></span>
Beranda
</li>
<li id="navPages" class="nav">
<span class="icon-document-alt-stroke"></span>
Data Profil
<ul class="subNav">
<li>Peta Lokasi</li>
<li>Site Plan</li>
</ul>
</li>
You can use something like this:
$(selector).click(function(){
$(this).removeClass(your class)
.addClass('active');
});
You have to define the selector you want to do something.

.click() functionality when clicking elements

Basically i want to click on a tab and a drop down menu appears then when you re-click the same tab or any of the others I want it to hide that tab/show the other tab if clicked on the same/other tab.
I tried
$('.click').click(function() {
$(this).find('.sub-nav-list').toggleClass('active');
});
and tried
$('.click').click(function() {
$('.sub-nav-list').removeClass('active');
$(this).find('.sub-nav-list').toggleClass('active');
});
but cant work it out! any insight? Thanks
html:
<nav class="secondary-nav">
<ul class="list clearfix">
<li class="leaders click">Leadership <span class="arrow">></span>
<ul class="sub-nav-list">
<li>Management</li>
<li>Board of Directors</li>
</ul>
</li>
<li class="contact click">Contact Info <span class="arrow">></span>
<ul class="sub-nav-list">
<li>Email Notification</li>
<li>Information Request</li>
</ul>
</li>
<li class="docs click">Documents <span class="arrow">></span>
<ul class="sub-nav-list">
<li>Governance Documents</li>
<li>Press Release</li>
<li>Reports & Presentations</li>
<li>Sec Filings</li>
<li>Frenquently Asked Questions</li>
<li>Tax Information</li>
</ul>
</li>
<li class="research click">Research <span class="arrow">></span>
<ul class="sub-nav-list">
<li>Dividends and Distributions</li>
<li>Stock Information</li>
<li>Analyst Coverage</li>
<li>Market Makers</li>
</ul>
</li>
</ul>
</nav>
I can see at least two possible issues there.
1) sub-nav-list is not a children of click element. If they are on the same level something like that might work:
$('.click').click(function() {
$(this).parent().find('.sub-nav-list').toggleClass('active');
});
2) You have these elements generated dynamically - so you need use on with selector of any parent element that exists before you dynamically generate your sub-menus (let say nav-list):
$(".click").on("click", ".nav-list", function() {
$(this).parent().find('.sub-nav-list').toggleClass('active');
});

Categories