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]);
});
Related
Hello so I have this problem, I use magento and my I can't find a place how to switch my tabs in position so I thought JQuery could come in hand. So this is what i have as an example
<li id="tab-4">
<li id="tab-3">
<li id="tab-2">
<li id="tab-1">
And i need to make it
<li id="tab-1">
<li id="tab-2">
<li id="tab-3">
<li id="tab-4">
Is there a fast way to do it? Or I have to do it one by one?
I guess you have an <ul> around you <li>
ul = $('ul'); // your parent ul element
ul.children().each(function(_,li){ul.prepend(li)})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li id="tab-4">4</li>
<li id="tab-3">3</li>
<li id="tab-2">2</li>
<li id="tab-1">1</li>
</ul>
Pure JS solution.
var a = document.getElementsByTagName('li');
var b = document.getElementById('list');
var arr = [];
Array.from(a).forEach(v => arr.push(v));
arr.reverse().forEach(v => b.append(v));
<ul id='list'>
<li id="tab-4">4</li>
<li id="tab-3">3</li>
<li id="tab-2">2</li>
<li id="tab-1">1</li>
</ul>
Also, for a sollution working (actually sorting) regardless of the initial order you can use sort() and append like this:
$("ul li").sort(function(a,b){
if(a.id.substring(4, 5) < b.id.substring(4, 5)) {
return -1;
} else {
return 1;
}
}).each(function() { $('ul').append(this);});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li id="tab-4">4</li>
<li id="tab-1">1</li>
<li id="tab-3">3</li>
<li id="tab-2">2</li>
</ul>
$(".list > li").detach().sort(function(a, b) {
return +a.id.replace("tab-","") - b.id.replace("tab-","") ;
}).appendTo("ul.list");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li id="tab-3">3
<li id="tab-4">4
<li id="tab-2">2
<li id="tab-1">1
</ul>
If your HTML code like this you can write your code using detach and a single appendTo like this.
More about detach(): https://www.w3schools.com/jquery/html_detach.asp
Fiddle: http://jsfiddle.net/fyrx459k/
Script:
$(function() {
$('.ul1 li').click( function(e) {
e.preventDefault();
var liIndex = $(this).index('li');
console.log(liIndex);
);
});
HTML:
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
How can I modify the script to have the following:
When a parent LI (Test#) is clicked the console will display the index - for example, clicking on Test4 will output a 3 (fourth item)
When clicking on a sub LI (Test# - #) it will display the parent index and the child index - for example, clicking on Test3 - 1 will output 2.0 (2 being the parent LI and 0 being the first child sub LI)
This is one way of doing it:
$(function () {
$('.ul1 li').click(function (e) {
e.preventDefault();
e.stopPropagation();
var i = $(this).parentsUntil('#ul1').add(this).map(function () {
return this.tagName === 'LI' ? $(this).index() : null;
}).get().join('.');
});
});
A pretty basic solution using $(this).parents("li")
$(function() {
$('.ul1 li').click(function(e) {
e.preventDefault();
e.stopPropagation();
var liIndex = "";
var $parents = $(this).parents("li");
if ($parents.length > 0)
liIndex += ($parents.index() + 1) + ".";
liIndex += ($(this).index() + 1);
alert(liIndex);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test
</li>
<li>Test2
</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1
</li>
<li>Test3 - 2
</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1
</li>
<li>Test4 - 2
</li>
</ul>
</li>
</ul>
I love html5 tags, so check if this solution can be useful. Otherwise you can do the same thing with the ID or whatever you prefer.
function checkIndex(element) {
deepCheck(element, '');
}
function deepCheck(element, index) {
if($(element).data('index') && $(element).is('li')) {
var newIndex = '';
if(index.length === 0) {
newIndex = 'Element indexes: ' + $(element).data('index')
} else {
newIndex = index + ' - ' + $(element).data('index');
}
deepCheck($(element).parent(), newIndex);
} else if($(element).data('root')) {
alert(index);
} else {
deepCheck($(element).parent(), index)
}
}
$(document).ready(function() {
$('a').click(function(e) {
e.preventDefault();
checkIndex(this);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul data-root="true" class="ul1" id="ul1">
<li data-index="1">Test</li>
<li data-index="2">Test2</li>
<li data-index="3">Test3
<ul class="ul2">
<li data-index="1">Test3 - 1</li>
<li data-index="2">Test3 - 2</li>
</ul>
</li>
<li data-index="4">Test4
<ul class="ul2">
<li data-index="1">Test4 - 1</li>
<li data-index="2">Test4 - 2</li>
</ul>
</li>
</ul>
Use parents('li') to check if the clicked li has a li ancestor, .index() to determine the index of a li, .preventDefault() to stop the click from following the link and .stopPropagation to stop event from bubbling. This should do it:
$('#ul1 li').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var arr = [];
arr.push( $(this).index() );
!$(this).parents('li').length ||
arr.push( $(this).parents('li').index() );
console.log( arr.reverse().join('.') );
});
$(function() {
$('#ul1 li').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var arr = [];
arr.push( $(this).index() );
!$(this).parents('li').length ||
arr.push( $(this).parents('li').index() );
console.log( arr.reverse().join('.') );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
I would suggest returning false. It removes the need to use both preventDefault and stopPropagation, and also to store the event in e.
Further, some more structured selections would be helpful here. There are only two cases to handle, where a parent element classed ul2 exits and where not. In the case it does, there needs to be two queries to determine the parents index and the current index with regards to the ul2 element. In the case where it does not, then only the relative ul1 index needs to be determined.
I included some extra elements to show the need for a more targeted approach.
$(function(){
$('.ul1 li').click(function() {
var ul2 = $(this).closest('.ul2'),
location = ul2.length > 0 ?
ul2.parent().index('.ul1 > li')+"."+ul2.find('li').index(this) :
$(this).index('.ul1 > li');
log(location);
return false;
});
});
function log(msg){ $("#result").text(msg); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
<div id="result"></div>
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
}
}
Please take a look at this FIDDLE. I have two pairs of unordered lists, each of which is inside a div element.pricing-table. The following code can find the li with the same classes, get the max height and set the height of all of them to the same. But I want to limit it to getting the max-height of each pair of lists inside each div element.
I think this line is giving me problem because it is getting all the lists with the same classes in the document:
var elems = $('.pricing-table ul li.' + elem.className),
I don't think I can use $(this) and update it like $(this +elem.className). Any suggestions?
Jquery script:
$(document).ready( function(){
$('.pricing-table ul li').each(function(i, elem) {
var elems = $('.pricing-table ul li.' + elem.className),
heights = $.map(elems, function(li) {
return $(li).height();
}),
max = Math.max.apply(null, heights);
elems.height(max);
});
});
HTML
<div class="pricing-table">
<ul>
<li class="heading">Bronze</li>
<li class="year">2003<p>(Text)..........</li>
<li class="package">Starter package</li>
<li class="location">Africa (Text).......)</li>
<li class="description">Text............ </li>
</ul>
<ul class="feature">
<li class="heading">Silver</li>
<li class="year">2004</li>
<li class="package">Intermediate package</li>
<li class="location">Asia</li>
<li class="description">Text............ </li>
</ul>
</div>
<div class="pricing-table">
<ul>
<li class="heading">Bronze</li>
<li class="year">2003<p>(Text)..........</li>
<li class="package">Starter package</li>
<li class="location">Africa (Text).......)</li>
<li class="description">Text............ </li>
</ul>
<ul class="feature">
<li class="heading">Silver</li>
<li class="year">2004</li>
<li class="package">Intermediate package</li>
<li class="location">Asia</li>
<li class="description">Text............ </li>
</ul>
</div>
You’d need to get only the li that are descendants of your current .pricing-table element, so you’ll have to iterate over the latter first:
$(document).ready(function () {
$('.pricing-table').each(function (i, e) {
$(e).find('ul li').each(function (i, elem) {
var elems = $(e).find('ul li.' + elem.className),
heights = $.map(elems, function (li) {
return $(li).height();
}),
max = Math.max.apply(null, heights);
elems.height(max);
});
});
});
… or something like that. http://jsfiddle.net/p3sfy/3867/
(Still kinda ugly, since it will iterate over the li multiple times, so that’s rather just a “quick fix” – but I don’t wanna think about anything more sophisticated here before I have not first heard a convincing argument why this data is not marked up using tables in the first place …?)
Let's say I have a list of items under a div or UL. I want to take all the list items with the same title attribute and wrap a UL around it. The next part though is that I want that UL to be under the LI with the same attribute. So, I'm trying to group basically.
So.... I start with.....
<li>Insurance</li>
<li>Education</li>
<li>Sports</li>
<li>Construction</li>
<li title ="Insurance">Malpractice</li>
<li title ="Construction">Carpentry</li>
<li title ="Education">College</li>
<li title ="Insurance">Automobile</li>
<li title ="Education">High School</li>
<li title ="Construction">Iron Worker</li>
and I want to get to......
<li>Insurance
<ul>
<li title ="Insurance">Malpractice</li>
<li title ="Insurance">Automobile</li>
</ul>
</li>
<li>Education
<ul>
<li title ="Education">College</li>
<li title ="Education">High School</li>
</ul>
</li>
<li>Sports</li>
<li>Construction
<ul>
<li title ="Construction">Carpentry</li>
<li title ="Construction">Iron Worker</li>
</ul>
</li>
Any help would be appreciated. Obviously new to the jquery and javascript world so I'm trying to wrap my brain around this.
Input:
<div id="stuffs">
<li>Insurance</li>
<li>Education</li>
<li>Sports</li>
<li>Construction</li>
<li title ="Insurance">Malpractice</li>
<li title ="Construction">Carpentry</li>
<li title ="Education">College</li>
<li title ="Insurance">Automobile</li>
<li title ="Education">High School</li>
<li title ="Construction">Iron Worker</li>
</div>
jQuery:
$("#stuffs li").each(function(){
$("#stuffs li[title='"+$(this).text()+"']").appendTo($(this)).wrapAll("<ul />");
});
Output:
<div id="stuffs">
<ul>
<li>Insurance
<ul>
<li title="Insurance">Malpractice</li>
<li title="Insurance">Automobile</li>
</ul>
</li>
<li>Education
<ul>
<li title="Education">College</li>
<li title="Education">High School</li>
</ul>
</li>
<li>Sports</li>
<li>Construction
<ul>
<li title="Construction">Carpentry</li>
<li title="Construction">Iron Worker</li>
</ul>
</li>
</ul>
</div>
Smile :-)
Demo here
// first we fetch all items without title attribute
var topLevel = $('li:not([title])');
// for each of those...
topLevel.each(function() {
var li = $(this),
// ... we get its text ...
title = li.text(),
// ... and other li elements with the corresponding title
children = $('li[title="' + title + '"]');
// if there are any...
if (children.length > 0) {
// ... create an empty list ...
var ul = $('<ul></ul>');
// ... fill it and ...
children.appendTo(ul);
// ... append it to the original li element
ul.appendTo(li);
}
});
jQuery documentation: :not(), [title], each(), appendTo()
This should work
$('#id li:not([title])').append('<ul />');
$('#id li[title]').each(function() {
$(this).appendTo('#id li:contains(' + $(this).attr('title') + ') ul');
})
A demo