Add count classes for nested list elements with jQuery - javascript

I have this HTML:
<ul class="parent">
<ul>
<li>
<ul></ul>
</li>
<li>
<ul>
<li>
<ul></ul>
</li>
</ul>
</li>
</ul>
</ul>
I need to add count classes for all nested lists in this markup, to reach this:
<ul class="parent">
<ul class="level-1">
<li>
<ul class="level-2"></ul>
</li>
<li>
<ul class="level-2">
<li>
<ul class="level-3"></ul>
</li>
</ul>
</li>
</ul>
<ul class="level-1">
<li>
<ul class="level-2"></ul>
</li>
<li>
<ul class="level-2">
<li>
<ul class="level-3"></ul>
</li>
</ul>
</li>
</ul>
</ul>
So i do this:
var parent_ul = $('.parent');
if (parent_ul.doesExist()){
var parent_ul_lists = parent_ul.find('ul');
parent_ul_lists.each(function(){
var i;
for (i = 0; i < parent_ul_lists.length; i++) {
$(this).eq(i).addClass('level-' + i);
}
})
}
But in output i have class test level-1 for all of parent list childrens. Can anybody help?

Try this
$('.parent ul').addClass(function(){
return "level-"+$(this).parents('ul').length;
});
DEMO

Try this
var parent = $('.parent').children();
next = parent;
var i = 0;
while (next.length) {
parent = next;
parent.addClass("Level_" + i);
i++;
next = next.children();
}
Demo

You need some good 'ole recursion!
Check out this JSFiddle UPDATE: corrected jsFiddle link
Here is the code:
function labelChildUL(element, count) {
element.children().each(function (index, value) {
var $me = $(value);
if ($me.is("ul")) {
$me.addClass("level-" + (count + 1));
labelChildUL($me, count + 1);
}
else
{
labelChildUL($me, count);
}
});
}
$(document).ready(function () {
var $parent = $('#parent');
labelChildUL($parent, 0);
});
I also updated your html to use id instead of class for "parent":
<ul id='parent'>
...

You can use this;
var parent_ul = $('.parent');
var parent_ul_lists = parent_ul.find('ul');
parent_ul_lists.each(function(){
$(this).addClass('level-'+ ($(this).parents().length -1)/2);
});
See working demo here: http://jsfiddle.net/huseyinbabal/qmGcC/
Note: Inspect element in output to see class assigned

Related

Add classes to two level navigation with javascript

I have a simple navigation with two levels. The li-elements of the first level shall get class="n11", that of the second class="n12".
This will write class="n11" to every li-element.
var firstNavi = document.getElementsByClassName("nav1-1");
for(var i = 0; i < firstNavi.length; i++) {
var firstLi = firstNavi[i].querySelectorAll("li");
for(var i = 0; i < firstLi.length; i++) {
firstLi[i].classList.add("n11");
}
}
<ul class="nav1-1">
<li >1.1.</li>
<li >1.2
<ul class="nav1-2">
<li>1.2.1</li>
<li>1.2.2</li>
</ul>
</li>
<li>1.3
<ul class="nav1-2">
<li>1.3.1</li>
<li>1.3.2</li>
</ul>
<li>1.4</li>
</ul>
How to achieve that is written class="n12" to the second li-elements and class="n11" only to the first level entries? Thanks for any help.
You can just retrieve the first level <li> elements as well as the second level <li> elements by using the child combinator > on the first level parent <ul> element and the second level <ul> parent element and now you can just loop through each list element and add the class name accordingly like this:
const firstLevel = document.querySelectorAll('.nav1-1 > li');
const secondLevel = document.querySelectorAll('.nav1-2 > li');
for (var i = 0; i < firstLevel.length; i++) {
firstLevel[i].classList.add('n11');
}
for (var i = 0; i < secondLevel.length; i++) {
secondLevel[i].classList.add('n12');
}
<ul class="nav1-1">
<li >1.1.</li>
<li >1.2
<ul class="nav1-2">
<li>1.2.1</li>
<li>1.2.2</li>
</ul>
</li>
<li>1.3
<ul class="nav1-2">
<li>1.3.1</li>
<li>1.3.2</li>
</ul>
<li>1.4</li>
</ul>
If you do not care about IE 11 compatibility or you are using a JavaScript compiler like Babel, you can further shorten and simplify the above JavaScript by using the forEach() method and arrow functions like this:
const firstLevel = document.querySelectorAll('.nav1-1 > li');
const secondLevel = document.querySelectorAll('.nav1-2 > li');
firstLevel.forEach(e => e.classList.add('n11'));
secondLevel.forEach(e => e.classList.add('n12'));
<ul class="nav1-1">
<li >1.1.</li>
<li >1.2
<ul class="nav1-2">
<li>1.2.1</li>
<li>1.2.2</li>
</ul>
</li>
<li>1.3
<ul class="nav1-2">
<li>1.3.1</li>
<li>1.3.2</li>
</ul>
<li>1.4</li>
</ul>
You can use the ">" query selector to find li elements that have a parent of .nav1-1, then add class n11 to each. Rinse and repeat for the li elements that have a parent of .nav1-2.
Here it is in code.
'use strict';
const li1s = document.querySelectorAll('.nav1-1 > li');
for (const li of li1s)
li.classList.add('n11');
const li2s = document.querySelectorAll('.nav1-2 > li');
for (const li of li2s)
li.classList.add('n12');
<ul class="nav1-1">
<li >1.1.</li>
<li >1.2
<ul class="nav1-2">
<li>1.2.1</li>
<li>1.2.2</li>
</ul>
</li>
<li>1.3
<ul class="nav1-2">
<li>1.3.1</li>
<li>1.3.2</li>
</ul>
<li>1.4</li>
</ul>

add each class for each parent li in navbar

my html structure is like this
<ul>
<li>items1</li>
<li>items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li>items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li>items4</li>
</ul>
I want to add classes for each parent li like below, using JavaScript is there any possibility to do this?
<ul>
<li class="a">items1</li>
<li class="b">items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li class="c">items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li class="d">items4</li>
</ul>
Using not() filter and addClass(function)
$('li').not('li li').addClass(function(i) {
return String.fromCharCode(i + 97)
})
.a {color:red}
.b {color:orange}
.c {color:green}
.d {color:blue}
li li {color:black}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>items1</li>
<li>items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li>items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li>items4</li>
</ul>
var letters = "abcd";
$("ul").first().children().each(function(index, el)
{
$(el).addClass(letters[index]);
});
Assuming that there could be n number of list items, we can use: String.fromCharCode(97 + index) to get the letter (up to z).
$("ul").first().children("li").each((index, item) => {
const letterFromIndex = String.fromCharCode(97 + index);
let $item = $(item);
$item.addClass(letterFromIndex);
});
If we want add different names for the li u can use this code also
var names = ["ab", "bc", "cd", "de"];
$("ul").first().children().each(function(index, el)
{
$(el).addClass(names[index]);
});

How to select phone number and contact from html element using jQuery?

I want to select phone number and contact name from html form and not able to select it with my code. I don't know what is wrong?
<ul class="contact-list">
<li>
<div class="phone">0128685665</div>
(Mike Lau)
</li>
<li>
<div class="phone">0242342354</div>
(John Son)
</li>
<li>
<div class="phone">012343534</div>
(Sam)
</li>
</ul>
and here is my code
var contact=[];
$('.contact-list').eq(0).find('li').find('.phone').each(function (i,elem){
contact.push($(elem).text().replace(/[A-Za-z\s]+/,'').trim());
});
for(var i=1;i<contact.length;i++){
console.log(contact[i]);
}
How can I select all phone numbers and contact names? Thanks in advace
$(".phone").each(function(){
var name = $(this).parent().clone().children().remove().end().text();
var phonenumber = $(this).text();
contact.push({name: name, phoneNumber: phonenumber});
});
console.log(contact);
created this fiddle for you
var contact=[];
$('.contact-list li ').each(function (i,elem){
contact.push( {
phone : $( this ).find('.phone').html(),
contact : $.trim( $( this ).clone().children().remove().end().text() ),
} );
});
for(var i=0;i<contact.length;i++){
console.log(contact[i]);
}
or simply just
$('.contact-list li ').each(function (i,elem){
contact.push( $.trim( $( this ).clone().children().remove().end().text() );
});
i think this is work fine for you.
var contact=[];
$('.contact-list li').each(function (i,item){
contact.push($(item).find(".phone").text().replace(/[A-Za-z\s]+/,'').trim());
});
for(var i=1;i<contact.length;i++){
alert(contact[i]);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<ul class="contact-list">
<li>
<div class="phone">0128685665</div>
(Mike Lau)
</li>
<li>
<div class="phone">0242342354</div>
(John Son)
</li>
<li>
<div class="phone">012343534</div>
(Sam)
</li>
</ul>
You can easily add span or div to names and fetch them into object, later which adds into array.
Please see code for html
var contact=[];
$('.contact-list').eq(0).find('li').each(function (key,value){
var phone = $(value).find('.phone').text().replace(/[A-Za-z\s]+/,'').trim();
var name = $(value).find('.name').text().trim();
contact.push({"name":name,"phone":phone});
});
for(var i=0;i<contact.length;i++){
alert(("name " + contact[i].name) + " and " + "phone " + contact[i].phone);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="contact-list">
<li>
<div class="phone">0128685665</div>
<span class="name"> (Mike Lau)</span>
</li>
<li>
<div class="phone">0242342354</div>
<span class="name">(John Son)</span>
</li>
<li>
<div class="phone">012343534</div>
<span class="name">(Sam)</span>
</li>
</ul>
You can also will need onload function or ondocumentready so your code runs as soon as page loads, or when you perform some action it will be triggered.
You should include the names in a separate tab as well. Some thing like this:
<ul class="contact-list">
<li>
<div class="phone">0128685665</div>
<div class="name">(Mike Lau)</div>
</li>
<li>
<div class="phone">0242342354</div>
<div class="name">(John Son)</div>
</li>
<li>
<div class="phone">012343534</div>
<div class="name">(Sam)</div>
</li>
</ul>
Then you can easily fetch names and phones using jQuery.
This should work, here is a demo jsFiddle.
jQuery
// array list of contacts:
var contacts = [];
// contact class:
function contact(name, phone) {
this.name = name,
this.phone = phone
}
// retrieve contact info from the DOM:
$('.contact-list li ').each(function(index, element) {
var phone = $(this).find('.phone').text();
var name = $.trim($(this).children().remove().end().text());
var person = new contact(name, phone);
contacts.push(person);
});
// view all contacts in array list:
for (var i = 0; i < contacts.length; i++) {
console.log(contacts[i].name, contacts[i].phone);
}

Next child LI that is wrapped in a different UL

I have the following list:
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li class="item">Three
<ul>
<li class="item">Something Original</li>
<li class="item selected">Something</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
Using jQuery, how do I find the next li with the class="item" since it is wrapped in a different container. Obviously I cannot do $(".selected").next(".item") so how else can I do it?
JSFiddle: http://jsfiddle.net/q3f6v7zz/
Since the li elements are nested and you know that you want the next appearing li with a particular class, you can use .index() and do something like this
var $li = $('.item'); // <--- get the list of all lis with class .item
var index = $li.index($('.selected')); // <--- find the index of the one with .selected amongst all the lis
console.log($li.eq(index+1).html()); // <--- index+1 because you need the next appearing li after selected
If you want to move the selected class on keydown something like this should do
var $li = $('.item');
$(document).on('keydown', function(e) {
if (e.keyCode == 40) {
var index = $li.index($('.selected'));
$li.eq(index).removeClass('selected');
index = (index+1) % $li.length; // <--- to rotate the values from 0 to count of li.item elements
$li.eq(index).addClass('selected');
}
});
var $li = $('.item');
$(document).on('keydown', function(e) {
if (e.keyCode == 40) {
var index = $li.index($('.selected'));
$li.eq(index).removeClass('selected');
index = (index+1) % $li.length;
$li.eq(index).addClass('selected');
}
});
.selected {
background: green;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li>Three
<ul>
<li class="item">Something</li>
<li class="item selected">Something Else</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
You can get the index of the selected element within all lis, and then increment that index to get the next one.
$("ul").on("click", "li.item.selected", function() {
var all_li = $("li.item");
var selected_index = all_li.index(this);
var next_li = all_li.eq((selected_index + 1) % all_li.length);
$(this).removeClass("selected");
next_li.addClass("selected");
});
.item.selected {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li class="item">Three
<ul>
<li class="item selected">Something</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
I used the modulus so it will wrap around at the end.
Not sure what you are exactly looking for but you can use $(Element").parent().parent().find("li");
So in other words .parent() may be what you are looking for there is also .sibling() to find or you may want $('li').closest('ul').find('li')
which will go up the tree to find the nearest ul to the one you are looking for
https://api.jquery.com/closest/
You may also use:
Vanilla JS to do something similar to what was discussed by others with $index if it makes more sense to you:
Again this isn't as efficient but that is basically what JQuery is doing:
var myLis = document.getElementsByTagName('li');
var wantedIndex;
for(var i = 0;i<myLis.length; i++){
if(myLis[i].className === "active"){
wantedIndex = i+1; //gets the li which is next when selecting all lis
}
}

Jquery prevent html list going over multiple lines

I want to prevent my users on a cms from making their menu item go over multiple lines as it doesn't look to good and can cut off their content. I so far have this.
<div id="sitewrap">
<div id="wrap">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact
<ul>
<li>Sub contact</li>
</ul>
</li>
<li>Register</li>
<li>Info</li>
<li>Share</li>
<li>Extra Info</li>
<li>Extra Info</li>
</ul>
</div>
</div>
If the width of the nav goes onto a second line I want the menu to look like this.
<div id="wrap">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
<li>Register</li>
<li>
More
<ul>
<li>Share</li>
<li>Extra Info</li>
<li>Extra Info</li>
</ul>
</li>
</ul>
</div>
I am trying to achieve this with Jquery but am stuck. See Fiddle (the second list in the fiddle is how I would want it to look)
I can count the width of the list items. But I want to say if the width is > 300 add all li that come after li = 300 to a sub ul of more like I have shown above in how I want it to look like. Any help here would be appreciated.
<script>
$(document).ready(function() {
var listWidth = [];
$('#wrap ul li').each(function() {
listWidth.push($(this).width());
});
var total = 0;
for (var i = 0; i < listWidth.length; i++) {
total += parseInt(listWidth[i]);
}
if (total > 300)
{
alert ('to big');
}
else {
alert ('nice');
}
});
</script>
try something like this, FIDDLE
$(document).ready(function() {
var listWidth = [];
var total = 0;
// new li to append
var li = $('<li><a>more</a></li>')
// new ul to be appended to ul
var ul = $('<ul>')
// variable to store index of element after which new li(more) will be added
var $index = true;
// variable to state that index vaiable is set, no more index need to be set
var $value_set = true;
$('#wrap ul li').each(function() {
total += parseInt($(this).width());
if (total > 300){
if($value_set){
$index = $(this).index() - 2;
$value_set = false;
}
}
});
$( "#wrap ul li:gt("+$index +")").each(function() {
ul.append(this);
});
if(ul.length){
$('#wrap ul').append(li.append(ul));
}
});

Categories