Accordion only toggle first item - javascript

I have the code below in my index.php, only the first item in the accordion shows.
For instance: when I click on Status or Repeated, am expecting the sub-menu of the clicked item but instead I get the result from the first list. That is Position.
<style>
ul .sub_main{
cursor: pointer;
}
.nested {
display: none;
}
.active {
display: block;
}
</style>
<ul class="sidebar-menu" data-widget="tree">
<li class="header">MANAGE</li>
<li class="sub_main"><i class="fa fa-users"></i><span>Positions</span><i class="fa fa-plus" aria-hidden="true"></i>
<ul class="nested">
<li class=""><i class="fa fa-users"></i> <span>a link 1</span></li>
<li class=""><i class="fa fa-users"></i> <span>a link 2</span></li>
</ul>
</li>
<li class="sub_main"><i class="fa fa-tasks"></i> <span>Status</span><i class="fa fa-plus" aria-hidden="true"></i>
<ul class="nested">
<li class=""><i class="fa fa-tasks"></i> <span>b link 1</span></li>
<li class=""><i class="fa fa-tasks"></i> <span>b link 2</span></li>
<li class=""><i class="fa fa-tasks"></i> <span>b link 3</span></li>
</ul>
</li>
<li class="sub_main"><i class="fa fa-tasks"></i> <span>Repeated</span><i class="fa fa-plus" aria-hidden="true"></i>
<ul class="nested">
<li class=""><i class="fa fa-tasks"></i> <span>c link 1</span></li>
<li class=""><i class="fa fa-tasks"></i> <span>c link 2</span></li>
</ul>
</li>
</ul>
this is the script to show the accordion item when clicked.
var toggler = document.getElementsByClassName("sub_main");
var i;
for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function() {
this.parentElement.querySelector(".nested").classList.toggle("active");
});
}

Your JS line with the class toggle method is being called on the parent of the "sub-main" class. This means that the querySelector is grabbing the first ".nested" element it finds from your ul.sidebar-menu element, which will always be the top ".nested" group.
If you simply remove the "parentElement" from that JS line, then the querySelector will look for the first ".nested" within the ".sub-main" (this) element.
Your JS should look like:
var toggler = document.getElementsByClassName("sub_main");
var i;
for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function() {
this.querySelector(".nested").classList.toggle("active");
});
}

Related

Getting values from a <ul>, <li> tree format

I've the folloing tree view:
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" />
<ul id="myTreeSelector" onClick="getPath()">
<li>
<span class="caret folder-selector"><i class="fa fa-folder"></i> first_folder</span>
<ul class="nested">
<li class="file"><i class="fa fa-file"></i> app1.dat</li>
<li class="file"><i class="fa fa-file"></i> app2.dat</li>
<li>
<span class="caret folder-selector"><i class="fa fa-folder"></i> second_folder</span>
<ul class="nested">
<li class="file"><i class="fa fa-file"></i> ret.dat</li>
</ul>
</li>
</ul>
</li>
</ul>
Which generates a folder tree like this:
What I'm loking for is that when I click on any file or folder, get the "full file/folder path". This means:
If I click in app1.dat, my desired output is: first_folder/app1.dat
If I click in second_folder, my desired output is: first_folder/second_folder
If I click in ret.dat, my desired output is: first_folder/second_folder/ret.dat
How can I archieve this? I tried with no luck to get the value:
function getPath() {
var value = $("#myTreeSelector").val()
console.log(value)
}
EDIT: The tree can have more than 2 levels, this is just a minified example.
Here is generic code, all you need to do is add event to li (using event delegation) and use parents to the li elements that are parents of selected li element.
$(function() {
$('#myTreeSelector').on('click', 'li', function() {
var item = $(this);
var path = [];
if (item.is('.file')) {
path.push(item.text().trim());
} else {
path.push(item.find('> .folder-selector').text().trim() + '/');
}
var parents = item.parents('#myTreeSelector li');
path = parents.map(function() {
return $(this).find('> .folder-selector').text().trim();
}).get().reverse().concat(path);
console.log(path.join('/'));
return false;
});
});
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" />
<ul id="myTreeSelector">
<li>
<span class="caret folder-selector"><i class="fa fa-folder"></i> first_folder</span>
<ul class="nested">
<li class="file"><i class="fa fa-file"></i> app1.dat</li>
<li class="file"><i class="fa fa-file"></i> app2.dat</li>
<li>
<span class="caret folder-selector"><i class="fa fa-folder"></i> second_folder</span>
<ul class="nested">
<li class="file"><i class="fa fa-file"></i> ret.dat</li>
<li><span class="caret folder-selector"><i class="fa fa-folder"></i> third_folder</span></li>
</ul>
</li>
</ul>
</li>
</ul>

Check whether a li element has any children with value using jQuery

I need to check if the each li element has any value or not using jQuery. I am providing my code below.
$("#navbarNavDropdown ul a").each(function() {
if ($(this).find('li').has("ul").length) {
alert('Yeah, we have a ul ' + $(this).text());
} else {
alert('Yeah, we dont have a ul ' + $(this).text());
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navbar-toggleable-sm collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul>
<li>Level 1
<ul>
<li>Level 2<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
<ul class="dropdown-menu s-drop">
<li>Jacksonville</li>
</ul>
</li>
</ul>
</li>
<li class="dropdown mega-drop pstatic">
Admissions<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
</li>
</ul>
</div>
My requirement is: suppose inside the loop 1st li element has some children(ul) value here I want to print the text and 2nd li element has no children(ul) so it will come under else part. If also check the submenu(i.e-Level 2) has any ul value or not. My code is not working as expected.
This code will work you fine.
$("#navbarNavDropdown ul a").each(function() {
if ($(this).closest('li').has("ul").length) {
alert('Yeah, we have a ul ' + $(this).text());
} else {
alert('Yeah, we dont have a ul ' + $(this).text());
$(this).find('span').remove(); //to remove the span
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navbar-toggleable-sm collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul>
<li>Level 1
<ul>
<li>Level 2<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
<ul class="dropdown-menu s-drop">
<li>Jacksonville</li>
</ul>
</li>
</ul>
</li>
<li class="dropdown mega-drop pstatic">
Admissions<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
</li>
</ul>
</div>
But as per me, there is a better piece of code for your requirement
$("#navbarNavDropdown > ul > li").each(function() {
if ($(this).has("ul").length) {
alert('Yeah, we have a ul ' + $(this).text());
} else {
alert('Yeah, we dont have a ul ' + $(this).text());
$(this).find('span').remove(); //to remove the span
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navbar-toggleable-sm collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul>
<li>Level 1
<ul>
<li>Level 2<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
<ul class="dropdown-menu s-drop">
<li>Jacksonville</li>
</ul>
</li>
</ul>
</li>
<li class="dropdown mega-drop pstatic">
Admissions<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
</li>
</ul>
</div>
I have changed the #navbarNavDropdown ul a to #navbarNavDropdown>ul>li so it will only loop 2 times [saving the time and only looping first level elements removing the span] and as per your comment, I think this is the code you looking for.
I hope this solves your Bug.
This will solve your problem.
$("#navbarNavDropdown ul li").each(function() {
if ($(this).find("ul").length) {
alert('Yeah, we have a ul ' + $(this).text());
} else {
alert('No, we dont have a ul ' + $(this).text());
$(this).find('span').remove();
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navbar-toggleable-sm collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul>
<li>Level 1
<ul>
<li>Level 2<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
<ul class="dropdown-menu s-drop">
<li>Jacksonville</li>
</ul>
</li>
</ul>
</li>
<li class="dropdown mega-drop pstatic">
Admissions<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
</li>
</ul>
</div>
The <a> elements do not have any child <ul> or <li> elements. The one <ul> is a sibling not a child.
If you meant it to be a child you need to change your html so that the closing </a> is after the closing </ul>. Note though since you have child <a> elements you won't be able to wrap the whole thing in the anchor as that is invalid html and the browser will not create such a structure.
You need to change your line to something that checks for siblings like:
$(this).next('ul').find('li ul').length
//Or go back up to the parent element and then go searching back down
$(this).parent().find('li ul').length
ul is not inside a element, so $(this).find('li').has("ul") couldn't work.
use $(this).next() get ul element.
An alternative.
$("#navbarNavDropdown ul").each(function() {
$.each(this.children, function(index, element) {
const text = element.innerText.split('\n').reverse()[0];
if (element.localName === 'li' && $(element).has('ul').length > 0) {
alert('Yeah, we have a ul ' + text);
} else {
alert('Yeah, we dont have a ul ' + text);
$(element).find('span').remove();
}
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navbar-toggleable-sm collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<ul>
<li>Level 1
<ul>
<li>Level 2<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
<ul class="dropdown-menu s-drop">
<li>Jacksonville</li>
</ul>
</li>
</ul>
</li>
<li class="dropdown mega-drop pstatic">
Admissions<span class="caret" data-toggle="dropdown"><i class="fa fa-caret-down" aria-hidden="true"></i></span>
</li>
</ul>
</div>

Add active class to li and parents through jquery

I'm a beginner to javascript, I've been trying to add the active class to a li using jquery i.e. When its clicked, expand li and make it active:
<script>
$(document).ready(function() {
var url = window.location['pathname'];
jQuery('li a').each(function() {
if($(this).attr('href') == url)
$(this).parent().addClass('active');
});
});
</script>
This only makes the sub-menu active but not expanded. But when I manually added the active class (as shown below) to treeview and li, it expanded and became active. How to dynamically add the active class through jquery?
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu" data-widget="tree">
<li class="header">MENU</li>
<li class="treeview active">
<a href="#">
<i class="fa fa-table"></i> <span>USER</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><i class="fa fa-plus"></i> Add</li>
<li class="treeview active">
<a href="#"><i class="fa fa-circle-o"></i> Profile
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="active"><i class="fa fa-circle-o"></i> View </li>
<li><i class="fa fa-circle-o"></i> Settings </li>
</ul>
</li>
</ul>
</li>
</ul>
</section>
</aside>
So, you need to apply active class on all .treeview using parents:
$(this).parents('.treeview').addClass('active');
Actually, changing parent() to parents() fixed it:
$(this).parents().addClass('active');

Check all li if one has class active then only parent ul addclass

Here I tried with my code but it's adding class="in" not only active parents but also other parents too. I want to add class only for active parent only not others.
$(function() {
$(".left_menu .nav-second-level li").each(function() {
if ($('.left_menu .nav-second-level li').hasClass('active')) {
$(this).parents('.left_menu .nav-second-level').addClass('in');
} else {
$(this).parents('.left_menu .nav-second-level').removeClass('in');
}
});
});
.active {
color: red;
background-color: red;
}
.in {
background-color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav" id="side-menu">
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Employee</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
create account
</li>
<li class="">
role set
</li>
<li class="active">
capability set
</li>
</ul>
</li>
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Department</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
Add department
</li>
<li class="">
Vew Deparment
</li>
</ul>
</li>
</ul>
You don't need to use each you can do it easily like following.
$('.left_menu .nav-second-level li').parent().removeClass('in')
$('.left_menu .nav-second-level li.active').parent().addClass('in')
Full Snippet
$('.left_menu .nav-second-level li').parent().removeClass('in')
$('.left_menu .nav-second-level li.active').parent().addClass('in')
.active {
color: red;
background-color: red;
}
.in {
background-color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav" id="side-menu">
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Employee</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
create account
</li>
<li class="">
role set
</li>
<li class="active">
capability set
</li>
</ul>
</li>
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Department</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
Add department
</li>
<li class="">
Vew Deparment
</li>
</ul>
</li>
</ul>
Within the each handler you need to use the this reference to the current element being iterated over. Your current code doesn't work as you're selecting all the li elements and checking if any of them has an active class. You can also use toggleClass with the boolean state flag to reduce your code. Try this:
$(".left_menu .nav-second-level li").each(function() {
$(this).parents('.left_menu .nav-second-level').toggleClass('in', $(this).hasClass('active'));
});
$(function() {
$(".left_menu .nav-second-level li").each(function() {
$(this).parents('.left_menu .nav-second-level').toggleClass('in', $(this).hasClass('active'));
});
});
.active {
color: red;
background-color: red;
}
.in {
background-color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav" id="side-menu">
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Employee</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
create account
</li>
<li class="">
role set
</li>
<li class="active">
capability set
</li>
</ul>
</li>
<li class="left_menu">
<a href="#">
<i class="fa fa-diamond"></i>
<span class="nav-label">Department</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
<li class="">
Add department
</li>
<li class="">
Vew Deparment
</li>
</ul>
</li>
</ul>
The problem is inside the .each, you're fetching all those elements again. This means you'll always target all elements. What you want to do is use the CURRENT element to check if it .hasClass, just like you did inside the if and else.
$(function() {
$(".left_menu .nav-second-level li").each(function() {
if ($(this).hasClass('active')) {
$(this).parents('.left_menu .nav-second-level').addClass('in');
} else {
$(this).parents('.left_menu .nav-second-level').removeClass('in');
}
});
});
$("#side-menu").find(".active").addClass("in");
$("#side-menu").find(".active").parent().addClass("in");
use the above code for your requirement achievement.
try this:
$(function() {
$(".left_menu .nav-second-level li").each(function() {
if ( $(this).hasClass('active') ) {
$(this).parent().addClass('in');
} else {
$(this).parent().removeClass('in');
}
});
});

jQuery remove class on slideUp

I have a class applied to the "sub-menu-click" div when a sub menu is opened. When another sub menu is opened, the script closes the previous one but I need it to also remove the "sub-menu-open" class applied to the previous sub-menu-click but without removing the class to the new sub-menu opened.
$('.sub-menu-click').click(function(){
$(this).next(".sub-menu").slideToggle(250);
$(this).addClass("sub-menu-open");
$(this).parent().parent().children().children().not($(this)).next('.sub-menu').slideUp(250);
return false;
});
<ul id="nav">
<li>
Dashboard
</li>
<li>
<div class="sub-menu-click">Clients</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Clients</li>
<li><i class="fa fa-angle-right"></i>Create a Client</li>
</ul>
</li>
<li>
<div class="sub-menu-click">Properties</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Properties</li>
<li><i class="fa fa-angle-right"></i>Create a Property</li>
</ul>
</li>
<li>
<div class="sub-menu-click">Appointments</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Appointments</li>
<li><i class="fa fa-angle-right"></i>Book an Appointment</li>
</ul>
</li>
<li>
<div class="sub-menu-click">Inventories</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Inventories</li>
<li><i class="fa fa-angle-right"></i>Create an Inventory</li>
</ul>
</li>
<li>
<div class="sub-menu-click">Check-Ins</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Check-Ins</li>
<li><i class="fa fa-angle-right"></i>Create a Check-In</li>
</ul>
</li>
<li>
<div class="sub-menu-click">Check-Outs</div>
<ul class="sub-menu">
<li><i class="fa fa-angle-right"></i>Lookup Check-Outs</li>
<li><i class="fa fa-angle-right"></i>Create a Check-Out</li>
</ul>
</li>
</ul>
Try this
$('.sub-menu-click').click(function(){
$(this).next('.sub-menu').slideToggle(250);
$(this).toggleClass('sub-menu-open');
});
It will toggle the class and the slide to achieve the result
Try this:
$('.sub-menu-click').click(function(){
$('.sub-menu-click').next(".sub-menu").slideUp(250);
$('.sub-menu-click').removeClass('sub-menu-click');
$(this).next(".sub-menu").slideToggle(250);
$(this).addClass("sub-menu-open");
});
$('.sub-menu-click').click(function(){
$("sub-menu-open").removeClass("sub-menu-open");
$(this).next(".sub-menu").slideToggle(250);
$(this).addClass("sub-menu-open");
$(this).parent().parent().children().children().not($(this)).next('.sub-menu').slideUp(250);
return false;
});

Categories

Resources