Why is my decision tree not working? - javascript

I am a beginner to coding, especially in HTML.
I have used the basic layout of this code that I found online (I can't seem to remember where), but I wanted a similar structure to this, and wanted to populate it with my own data.
I tried to put all the code from separate files, .js and .css part into the .html code. (I searched online how to do this, also I wasn't sure about jQuery, and found on https://www.w3schools.com/jquery/jquery_get_started.asp that I can add it into the <head> section instead of downloading the library? The code below doesn't use the jQuery, but I have no clue how to use it. Can this be inserted at the top of the .html file within the <script> tag?
Please can anyone tell me why this only shows up on my browser as three bullet points only, and when I hover over it, the mouse changes from arrow to pointer, but doesn't click/expand.
Any help will be much appreciated!
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for (var i = 0; i < tree.length; i++) {
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if (classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for (var i = 0; i < opensubs.length; i++) {
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
body {
font-family: Arial;
}
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open>ul {
display: block;
}
ul.tree li a {
color: black;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding: 0 .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
ul.tree li>a:not(:last-child):before {
content: '+';
}
ul.tree li.open>a:not(:last-child):before {
content: '-';
}
<ul class="tree">
<li>Part 1
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 2
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 3
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
</ul>

The :scope pseudo element isn't widely supported according to https://developer.mozilla.org/en-US/docs/Web/CSS/:scope but I'm not sure it was needed to acheive your goal. In fact, chrome and firefox worked fine for me and I just saw some javascript errors in IE and Edge - didn't test Safari.
This code is working for me in all of the tested browsers without javascript errors after simple removing :scope from the open sub element selector in the javascript.
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for (var i = 0; i < tree.length; i++) {
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if (classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll('.open');
for (var i = 0; i < opensubs.length; i++) {
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
body {
font-family: Arial;
}
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open>ul {
display: block;
}
ul.tree li a {
color: black;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding: 0 .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
ul.tree li>a:not(:last-child):before {
content: '+';
}
ul.tree li.open>a:not(:last-child):before {
content: '-';
}
<ul class="tree">
<li>Part 1
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 2
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 3
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
</ul>

Related

Javascript target only clicked element

So I have a side navigation that has a sub-menu in some of the list, and I'm trying to display the sub-menu only when it's clicked.
Here is the HTML
<div class="sidebar">
<ul class="nav">
<li class="main-menu" onclick="dispDrop()">Item 1
<ul class="sub-menu">
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 2</li>
<li>Item 3</li>
<li class="main-menu" onclick="dispDrop()">Item 4
<ul class="sub-menu">
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
Here is its CSS
.nav ul {
display: none;
position: relative;
padding: 0px;
}
.nav li.active ul {
display: block;
}
Here is the javascript
<script type="text/javascript">
const navItem = document.querySelector('.main-menu');
function dispDrop() {
navItem.classList.toggle("active");
}
</script>
At first it was working fine, but when I added a submenu to another list, it started glitching and won't display the submenu.
Is there a way to target only the clicked <li> and only add/toggle the class to that clicked <li>?
What you can do is adding this to onclick="dispDrop()"
And then do the following.
function dispDrop(obj) {
obj.classList.toggle("active");
}
Demo
function dispDrop(obj) {
obj.classList.toggle("active");
}
.nav ul {
display: none;
position: relative;
padding: 0px;
}
.nav li.active ul {
display: block;
}
<div class="sidebar">
<ul class="nav">
<li class="main-menu" onclick="dispDrop(this)">Item 1
<ul class="sub-menu">
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 2</li>
<li>Item 3</li>
<li class="main-menu" onclick="dispDrop(this)">Item 4
<ul class="sub-menu">
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
Some issues that I have Identified are listed below.
You are setting navItem as document.querySelector('.main-menu'). This will always returns the first DOM element with that class name. Not your required target.
Your click event will be triggering the click event of the anchor tag, that will result in reload of page.
I have fixed that by toggling the class list of the target elemet from the click tiggered. This will give the required target where the click is triggered.
Call e.preventDefault(); e.stopPropagation(); inside the click event to stop the click event triggering the anchor tag click event.
Working Fiddle
function dispDrop(e) {
e.currentTarget.classList.toggle("active");
e.preventDefault();
e.stopPropagation();
}
.nav ul {
display: none;
position: relative;
padding: 0px;
}
.nav li.active ul {
display: block;
}
<div class="sidebar">
<ul class="nav">
<li class="main-menu" onclick="dispDrop(event)">
Item 1
<ul class="sub-menu">
<li>Sub-item 11</li>
<li>Sub-item 11</li>
<li>Sub-item 11</li>
<li>Sub-item 11</li>
</ul>
</li>
<li>Item 2</li>
<li>Item 3</li>
<li class="main-menu" onclick="dispDrop(event)">
Item 4
<ul class="sub-menu">
<li>Sub-item 12</li>
<li>Sub-item 12</li>
<li>Sub-item 12</li>
<li>Sub-item 12</li>
</ul>
</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
I rewrite a little bit your code. The problem occurs from the anchor. You can
remove the anchor an style the li tag to have the anchor feeling (cursor: pointer; etc) or
you add a # to your href. that will avoid to follow the link
Then I pass with your onclick event the currecnt clickent object. Then you eventHandler knows which element was clicked.
function dispDrop(event) {
event.querySelector('ul').classList.toggle("hide");
}
.nav ul {
position: relative;
padding: 0px;
}
.hide {
display: none;
position: relative;
}
<div class="sidebar">
<ul class="nav">
<li class="main-menu" onclick="dispDrop(this)">
Item 1
<ul class="sub-menu hide">
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 2</li>
<li>Item 3</li>
<li class="main-menu clicki" onclick="dispDrop(this)">
Item 4
<ul class="sub-menu hide">
<li>Sub-item A </li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
<li>Sub-item 1</li>
</ul>
</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>

How to expand the nodes by default on page load

i have used the following code.Now i want to expand all the nodes by default on page load.can anyone suggest me how to do it
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++){
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if(classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for(var i = 0; i < opensubs.length; i++){
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
body {
font-family: Arial;
}
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open > ul {
display: block;
}
ul.tree li a {
color: black;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding:0 .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
ul.tree li > a:not(:last-child):before {
content: '+';
}
ul.tree li.open > a:not(:last-child):before {
content: '-';
}
<ul class="tree">
<li >Part 1
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 2
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 3
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
</ul>
Apply the class name of open to your list items <li> tag that you wish to expand by default. Simple find done by reading the source code which leads me to believe you don't really understand how the source code you're using works...
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for (var i = 0; i < tree.length; i++) {
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if (classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for (var i = 0; i < opensubs.length; i++) {
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
body {
font-family: Arial;
}
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open>ul {
display: block;
}
ul.tree li a {
color: black;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding: 0 .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
ul.tree li>a:not(:last-child):before {
content: '+';
}
ul.tree li.open>a:not(:last-child):before {
content: '-';
}
<ul class="tree">
<li class="open">Part 1
<ul>
<li class="open">Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li class="open">Part 2
<ul>
<li class="open">Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li class="open">Part 3
<ul>
<li class="open">Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li class="open">Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
</ul>
Update
As AVI has suggested: "you can also write something like tree[i].click(); before applying the event listener if you want that programmatically."
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for (var i = 0; i < tree.length; i++) {
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if (classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for (var i = 0; i < opensubs.length; i++) {
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
tree[i].click();
}

Not able to create a tree view with javascript with the code below

I'm trying to create a tree view with the help of a code that my friend sent me but it's not working in my browser. However, the code runs file on www.jsfiddle.com and doesn't seem to have any issues with it. Here's the link https://jsfiddle.net/te366hu2/2/
Below is how I'm trying to run this:
<html>
<head>
<title>Tree</title>
<style>
body {
font-family: Arial;
}
ul.tree li {
list-style-type: none;
position: relative;
}
ul.tree li ul {
display: none;
}
ul.tree li.open > ul {
display: block;
}
ul.tree li a {
color: black;
text-decoration: none;
}
ul.tree li a:before {
height: 1em;
padding:0 .1em;
font-size: .8em;
display: block;
position: absolute;
left: -1.3em;
top: .2em;
}
ul.tree li > a:not(:last-child):before {
content: '+';
}
ul.tree li.open > a:not(:last-child):before {
content: '-';
}
</style>
<script>
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++){
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if(classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for(var i = 0; i < opensubs.length; i++){
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
</script>
</head>
<body>
<ul class="tree">
<li>Part 1
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 2
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
<li>Part 3
<ul>
<li>Item A
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item B
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item C
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item D
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
<li>Item E
<ul>
<li>Sub-item 1</li>
<li>Sub-item 2</li>
<li>Sub-item 3</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
You're code seems to be correct; however, it's in the wrong spot. Move the entire script tags and their contents to the spot right before the closing body tag in your HTML.
<script>
var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++){
tree[i].addEventListener('click', function(e) {
var parent = e.target.parentElement;
var classList = parent.classList;
if(classList.contains("open")) {
classList.remove('open');
var opensubs = parent.querySelectorAll(':scope .open');
for(var i = 0; i < opensubs.length; i++){
opensubs[i].classList.remove('open');
}
} else {
classList.add('open');
}
});
}
</script>
</body>

iterate through li elements then .addclass css on some li elements

I'm iterating through li elements then applying css on some li elements that meets my criteria.
lets say i have a 15 total of li elements in ul then i will css class using javascript .addclass hide_me on li count 11 to 15.
this is the html:
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
<li>item 8</li>
<li>item 9</li>
<li>item 10</li>
<li>item 11</li>
<li>item 12</li>
<li>item 13</li>
<li>item 14</li>
<li>item 15</li>
</ul>
this i want to make using JavaScript/jquery
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
<li>item 8</li>
<li>item 9</li>
<li>item 10</li>
<li class="hide_me">item 11</li>
<li class="hide_me">item 12</li>
<li class="hide_me">item 13</li>
<li class="hide_me">item 14</li>
<li class="hide_me">item 15</li>
</ul>
So far i came up with this JavaScript code but its not working.
my Javascript:
<script>
$(document).ready(function(){
$.each($('.items'), function() {
var children = $(this).find(">li");
var count_items = children.length;
for (var items = 11; items < count_items; items++) {
//console.log(items); //output 11, 12, 13, 14, 15
$(".items li:nth-of-type("+ items +")").addClass('.hideme'); // this is css selector by nth-type
}
});
});
</script>
$('ul li:gt(9)').addClass('addedclass')
.addedclass{color:red}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
<li>item 8</li>
<li>item 9</li>
<li>item 10</li>
<li>item 11</li>
<li>item 12</li>
<li>item 13</li>
<li>item 14</li>
<li>item 15</li>
</ul>
Use :gt() selector. No need to iterate the li
Index start at 0
Description: Select all elements at an index greater than index within the matched set.
Try this
$("li").each(function(k,v){
if(k>9)
$(this).addClass("hide-me");
});
// Apply css on class applied
$(".hide-me").css({ 'color':'red'});
https://jsfiddle.net/sum1/yzubc169/

level indicator using jQuery

Can we add class at each level like below using Jquery/JS? So that we can identify that on which level of list we are..
<ul>
<li class="level1">level 1
<ul>
<li class="level2">level 2</li>
<li class="level2">level 2</li>
<li class="level2">level 2
<ul>
<li class="level3">level 3</li>
<li class="level3">level 3</li>
<li class="level3">level 3
<ul>
<li class="level4">level 4</li>
<li class="level4">level 4</li>
<li class="level4">level 4</li>
</ul>
</li>
</ul>
</li>
<ul>
</li>
<li class="level1">level 1</li>
<li class="level1">level 1</li>
</ul>
Try utilizing .each() , .parents() , .length
$("li").each(function(i,el) {
$(this).addClass("level" + $(this).parents("ul").length)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<ul>
<li>level 1
<ul>
<li>level 2</li>
<li>level 2</li>
<li>level 2
<ul>
<li>level 3</li>
<li>level 3</li>
<li>level 3
<ul>
<li>level 4</li>
<li>level 4</li>
<li>level 4</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>level 1</li>
<li>level 1</li>
</ul>
This is a way without needing to keep looking up the parents.
(function find(par, index) {
index += 1;
var lis = par.find("> li").addClass("level" + index);
if (lis.length) {
find(lis.find("> ul"),index);
}
}($("ul#start"),0))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<ul id="start">
<li>level 1
<ul>
<li>level 2</li>
<li>level 2</li>
<li>level 2
<ul>
<li>level 3</li>
<li>level 3</li>
<li>level 3
<ul>
<li>level 4</li>
<li>level 4</li>
<li>level 4</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>level 1</li>
<li>level 1</li>
</ul>
You can do this with a simple recursive function.
function addLevels(parent, level) {
parent = parent || $("body").children("ul");
level = level || 1;
var children = parent.children("li");
children.addClass("level" + level);
parent = children.children("ul");
if (parent.length)
addLevels(parent, ++level);
}
$(function() {
addLevels();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li>level 1
<ul>
<li>level 2</li>
<li>level 2</li>
<li>level 2
<ul>
<li>level 3</li>
<li>level 3</li>
<li>level 3
<ul>
<li>level 4</li>
<li>level 4</li>
<li>level 4</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>level 1</li>
<li>level 1</li>
</ul>
If you want some extra speed you can try a pure javascript solution. Here is a JsFiddle for some food for thought.
http://jsfiddle.net/fqp74r8j/
var listArr = document.querySelectorAll('ul');
[].forEach.call(listArr, function(el, i) {
var listLen = el.children.length;
for (var j = 0; j < el.children.length; j++) {
el.children[j].classList.add('level-' + (i + 1));
}
});

Categories

Resources