level indicator using jQuery - javascript

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));
}
});

Related

How can I get the index of a list item element not "display:none;"

I want to find the index of a list item element that has no attribute style="display:none;".
Here is my basic list:
<ol>
<li style="display:none;">LI 1</li>
<li>LI 2</li>
<li style="display:none;">LI 3</li>
<li style="display:none;">LI 4</li>
<li style="display:none;">LI 5</li>
</ol>
Thank you for your answers :)
While you could search for an element without a style attribute
const li = document.querySelector('ol li:not([style])');
console.log(li.textContent);
<ol>
<li style="display:none;">LI 1</li>
<li>LI 2</li>
<li style="display:none;">LI 3</li>
<li style="display:none;">LI 4</li>
<li style="display:none;">LI 5</li>
</ol>
If you're going to select elements based on the style display, I'd highly recommend using a class instead:
const li = document.querySelector('ol li:not(.hide)');
console.log(li.textContent);
.hide {
display: none;
}
<ol>
<li class="hide">LI 1</li>
<li>LI 2</li>
<li class="hide">LI 3</li>
<li class="hide">LI 4</li>
<li class="hide">LI 5</li>
</ol>
I think you can do like this.
const li = document.querySelector('li:not([style="display:none;"])');
console.log(li.textContent);
<ol>
<li style="display:none;">LI 1</li>
<li style="display:block;">LI 2</li>
<li style="display:none;">LI 3</li>
<li style="display:none;">LI 4</li>
<li style="display:none;">LI 5</li>
</ol>

Why is my decision tree not working?

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>

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>

Add a class to list at variable position

I have a variable set that represents an item in the list.
I also have the list:
<ul>
<li class="mylist">Item 1</li>
<li class="mylist">Item 2</li>
<li class="mylist">Item 3</li>
<li class="mylist">Item 4</li>
<li class="mylist">Item 5</li>
<li class="mylist">Item 6</li>
</ul>
What I need to do is to add a css class to the list thats in the position of the variable value.
For example:
If myVariable = '1' then list will look like this:
<ul>
<li class="mylist">Item 1</li>
<li class="mylist">Item 2</li>
<li class="mylist">Item 3</li>
<li class="mylist">Item 4</li>
<li class="mylist">Item 5</li>
<li class="mylist">Item 6</li>
</ul>
If myVariable = '3' then list will look like this:
<ul>
<li class="mylist">Item 1</li>
<li class="mylist">Item 2</li>
<li class="mylist">Item 3</li>
<li class="mylist">Item 4</li>
<li class="mylist">Item 5</li>
<li class="mylist">Item 6</li>
</ul>
and so on.
How can I do this?
var value = 3;
$('ul li.mylist a').filter(function () {
return $(this).text() === 'Item ' + value;
}).addClass('myclass');
You can use the eq method in jQuery for selecting element by index:
const myVariable = 3;
$('.mylist').eq(myVariable - 1).find('a').addClass('myClass');
Mind that eq assumes that your indices are 0-based (which means the first one is 0 and not 1). That's why it's myVariable - 1.
$("li.mylist").eq(position -1).find("a").addClass("myClass")

Wrap first level of "li" tags into one div using Jquery

Consider we have a multi-level html list that looks like this:
<ul class="catalog">
<li>
<ul>
<li>
<ul>
<li>subcat subcat 1</li>
<li>subcat subcat 2</li>
<li>subcat subcat 3</li>
</ul>
</li>
<li>subcat 2</li>
<li>subcat 3</li>
</ul>
</li>
<li>
<ul>
<li>subcat 4</li>
<li>subcat 5</li>
<li>subcat 6</li>
</ul>
</li>
</ul>
I need to wrap into one div only <li> tags (hamed "header 1", "header 2"... and all its children) which belong to first level of the list.
The result should be:
<ul class="catalog">
<div class="myWrapper">
<!-- Added by JQuery -->
<li>
<ul>
<li>
<ul>
<li>subcat subcat 1</li>
<li>subcat subcat 2</li>
<li>subcat subcat 3</li>
</ul>
</li>
<li>subcat 2</li>
<li>subcat 3</li>
</ul>
</li>
<li>
<ul>
<li>subcat 4</li>
<li>subcat 5</li>
<li>subcat 6</li>
</ul>
</li>
</div>
<!-- Added by JQuery -->
</ul>
I tried wrap() function but it did not work as expected
Any ideas how to do this job?
$('.catalog > li').wrapAll('<div class="wrapper"></div>');
But you're both starting and ending with seriously invalid HTML, so you should probably fix that then ask this question again.
First, let's start with valid HTML, like this:
<ul class="catalog">
<li>header 1
<ul>
<li>subcat 1
<ul>
<li>subcat subcat 1</li>
<li>subcat subcat 2</li>
<li>subcat subcat 3</li>
</ul>
</li>
<li>subcat 2</li>
<li>subcat 3</li>
</ul>
</li>
<li>header 2
<ul>
<li>subcat 4</li>
<li>subcat 5</li>
<li>subcat 6</li>
</ul>
</li>
</ul>​
Then you cap wrap them using .wrapAll(), like this:
$(".catalog > li").wrapAll("<li><div class='something'><ul></ul></div></li>");​
This results in valid HTML, like this:
<ul class="catalog">
<li>
<div class="something">
<ul>
<li>header 1
<ul>
<li>subcat 1
<ul>
<li>subcat subcat 1</li>
<li>subcat subcat 2</li>
<li>subcat subcat 3</li>
</ul>
</li>
<li>subcat 2</li>
<li>subcat 3</li>
</ul>
</li><li>header 2
<ul>
<li>subcat 4</li>
<li>subcat 5</li>
<li>subcat 6</li>
</ul>
</li>
</ul>
</div>
</li>
</ul>
You can test it out here, though you can probably get the effect you want with styling on the original <ul>, display: block for example.

Categories

Resources