I looked quite a bit for a solution for this but I surprisingly couldn't find anything. Maybe I just didn't search for the right words. I found a bunch of questions about getting the index by the element, but I need the opposite.
I'm trying to use javascript and jquery get an element in an ordered list by it's index in the list. For example, if I have this list:
<ol>
<li>Zero</li>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ol>
I would like to be able to get the first one (Zero) by its index of 0, or the second one (One) by its index of 1.
So far I have tried a few things:
A simple function based off of the getting the index of an object in a list using the id.
elem = list.index(0); //To get the first element, but this is not a thing.
A loop like this:
//elem is the element I am currently at.
//Starting at the last element and going to the first.
var elem = list.getLastChild(); //But list.getLastChild() is apparently
//not a thing although it is here ([w3c link][1]).
//Start at 0 and go to the index
//(may/may not need the = before num, but I think I do)
for(var i=0; i<=num; i++){
//Set elem to it's previous sibling
elem = elem.getPreviousSibling(); //getPreviousSibling is probably not a thing as
//well but I couldn't get that far before it broke anyway.
}
//Return the element at the index
return elem;
So is there a way to do this?
Thanks.
There are many ways to do this. You can use :eq selector. Something like this?
var $lis = $('ol li');
for(var i=0; i < $lis.length; i++)
{
alert($('ol li:eq(' + i + ')').text());
}
Demo
So, as this is zero indexed. You could do: $('ol li:eq(0)') for getting the first element.
You can also use css, nth-child, nth-of-type selector:
alert($('ol li:nth-child(1)').text()); // This starts with 1 index, non-zero indexed.
You can use JQuery:
$("ol li:nth-child(1)")
$("ol li:nth-child(n)")
http://api.jquery.com/nth-child-selector/
Related
I have an requirement in JS where, i want to get the count of li element which has the same inner value. What is the best way to do it ? I know we can achieve this in Jquery easily using find and contains but i don't want to use jquery.
I want the length of li elements has the Same Value.
For Eg: Say i want to find out how many LI has the value 'A'.
Below is the JS i have tried, which i think is not the best cos if i have say around 10,000 LI then i will have to loop through all the elements get their values and check if its what i want or no, which will surely hit the performance.
Note : LI element is added runtime with their Value.
HTML
<ul class="s_1" id="ULE">
<li class="r1">A</li>
<li class="r1">A</li>
<li class="r1">B</li>
<li class="r1">A</li>
</ul>
JS
var LI = document.getElementsByClassName('r1');
var cnt = 0;
for(var i=0;i<LI.length;i+=1){
if(LI[i].innerHTML == 'A'){
cnt += 1;
}
}
if(cnt === 4)
alert('working good!!');
JS Fiddle
I don't think there is a better way to improve the performance. If you have nothing but the DOM to work with (e.g. if the data is from user input), and not the underlying data structure from which you created the data, AFAICT there is no other structure to collect all of the elements than into an array-type structure, which will then require O(n) time to check every element.
Rather than have a count target, which is therefore dependent on the amount of list elements, try instead a function to handle the data, which increases the convenience somewhat:
function isEveryElementEqual(nodeList) {
val = nodeList[0].innerHTML;
for (var i=1; i<nodeList.length; i++) {
if (nodeList[i].innerHTML !== val) return false;
}
return true;
}
var LI = document.getElementsByClassName('r1');
console.log(isEveryElementEqual(LI)); // Returns false with the above HTML
You don't have to search all <li> in the document. getElementsByClassName can be applied to an element, it will then only search within that element. So you can do:
var LI = document.getElementById('ULE').getElementsByClassName('r1');
DEMO
You can also simplify this with querySelectorAll:
var LI = docuement.querySelectorAll('#ULE .r1');
I'm trying to identify a li element from a group of li inside of div
<div id="group">
<li></li>
<li></li>
<li></li>
</div>
its quite simple tho, i could give each li an unique id and this problem would be over. like
var listItem1,2,3 = document.getElementById('liItem1,2,3') etc
listItem1,2,3.addEventListener('click',function);
this might be handy when it comes to 1,2 or 3 elements but this is all static and when it start to scale its not possible anymore, Instead im trying to make use of NodeList.
var nodeList = document.getElementById('group').getElementsByTagName('li');
now i will have a NodeList with li 0, li 1, li 2
the problem comes now becouse i donĀ“t know how to trace which li is being clicked.
nodeList.addEventListener('click',function);
wont work here becouse it dosent know which one is being clicked at here.
nodeList[0].addEventListener('click',function);
is the same solution as above. How can i trace which of the li is being clicked at? only plain/raw javascript
To find the index of an element in response to an event, I'd suggest delegating the event-handling to an ancestor (rather than individually binding an event-handler to multiple child-elements):
// 'event' is passed in automagically (in non IE browsers, haven't tested IE):
function getIndexFrom(event){
// event.target is the element upon which the event was triggered:
var clicked = event.target,
// finding all the children of the parent of the clicked-element
// (could use 'this.children', as 'this' will be the 'ul' in this demo):
children = clicked.parentNode.children;
// iterating over those child elements:
for (var i = 0, len = children.length; i < len; i++){
// if the clicked element is the current element:
if (children[i] === clicked){
console.log('index is: ' + i)
// we return 'i' as the index:
return i;
}
}
// this shouldn't happen, assuming we're looking at the right group
// of elements, but it's there as an in-case and for debugging:
return false;
}
document.getElementById('group').addEventListener('click', getIndexFrom);
JS Fiddle demo.
References:
EventTarget.addEventListener().
for... loop.
ParentNode.children.
I have a handle on an Un-ordered List (for my example i will call the handle Var1) and would like to be able to assign its last li to a variable. I tried Lastli = var1.lastChild the only method I figured would work but it didn't. I can't seem to find a answer to this using only Javascript not jQuery any help is appreciated.
You can select the parent element and use the lastChild property.
var container = document.getElementsByTagName("ul")[0];
var lastchild = container.lastChild;
Or you select all the items into an array and get the last item. Here is a quick example:
var items = document.querySelectorAll("li");
var lastchild = items[items.length-1];
you can select all 'li' and take the last one. Something like:
var myLi = document.getElementsByTagName('li');
var lastLi = myLi[myLi.length-1];
Lets consider an example
<ul >
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
To get the last child of the list you can simply make use of queryselector
document.querySelector('li:last-child'); //this will return Milk which is the last child of the list
document.querySelector('li:first-child') OR document.querySelector('li'); //both will give you the first child of the list
Suppose you want the n-th child for that you can use the following syntax:
document.querySelector('li:nth-child(2)'); //it will return the second child (here Tea)
If you want all the list item in the given list:
document.getElementsByTagName('li') //(Will return the whole list)here i am using tagname. It can be also applied on classname or element id
Try this: .childNodes[childNodes.length - 1]
either ulReference.children[ulReference.children.length -1] or ulReference.childNodes[ulReference.childNodes.length -1]. The difference between the two can be found here
The simplest way is to use the document.querySelector and use the :last-child to get it.
Exemple:
const list = document.querySelector("li:last-child");
i'm running a contact-form-plugin on my wordpress installation. everything works fine but i want to style my form a little bit more. to do it like this i have to style some DIVs (which the plugin is processing) in a different way. the problem is: all DIV-containers have no IDs or classes! everything is processed by the plugin and my PHP-skills are like zero so i have to deal with this "naked" DIVs ;-)
the question is: is it possible to add serially numbered classes to each DIV on the current site via javascript?
thanks so far and i hope you get waht i mean (sorry for that shitty english)!
Yet another way, passing a callback to .attr [docs]:
$('div').attr('class', function(i) {
return 'someClass' + i;
});
Though you could also use this for IDs instead, since each class will be unique.
Note that you don't have to use IDs or classes to select elements, there are a number of selectors and traversal methods with which you can get a reference to the elements you want.
To prevent overriding existing classes, either select only the elements with no class or somehow narrow down the selection of divs to only those you want:
$('div:not([class])')
or use .addClass [docs] instead of .attr:
$('div').addClass(function(i) {
return 'someClass' + i;
});
You need something like this,
Live Demo
$('div').each(function(i, item){
$(this).attr('class', "YourClass" + i); //You can replace i with some other variable if required and increment it.
});
You could do this:
var divs = document.getElementsByTagName("div");
var className = "myClass";
for( var i = 0, max = divs.length; i< max; i++ ){
divs[i].setAttribute("class",className + i.toString());
}
Please consider the following code :
<!DOCTYPE html>
<html>
<style>
p{ width:200px; }
</style>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<p><span>Hello</span>, how are you?</p>
<p>Me? I'm <span>good</span>.</p>
<script>
$(document).ready(function(){$("p").find($("*")).andSelf().css("background- color","blue"); });
</script>
</body>
</html>
The output is the whole document turning into blue color while I only wanted the paragraph and span inside it to turn blue.
If I use $("p").find(" * ") instead of $("p").find($(" * ")) then everything shows according to my need. Can anyone work out the difference between the two approach?Thanks!
Note: Please everyone note that I know there are easier methods to do this stuff,but I just want to know why this didn't work..
Disclaimer: The other answers already suggest better selectors to
achieve your goal, but I understand you want to know why andSelf()
ends up matching all the elements in the document, so I'll try to
explain that.
First, as you know, andSelf() adds the previous set of elements on the stack to the current set. So, in your case, it seems it should add the <p> elements to the set containing their descendants:
$("p") // match the paragraphs
.find($("*")) // match all the elements that descend from a paragraph
.andSelf() // add the paragraphs to the elements above
However, the above assumes that find($("*")) is the previous set of elements, and that's simply not the case here. The first hint about this comes from the documentation for find():
As of jQuery 1.6, we can also filter the selection with a given jQuery
collection or element. With the same nested list as above, if we start
with:
var $allListElements = $('li');
And then pass this jQuery object to find:
$('li.item-ii').find( $allListElements );
This will return a jQuery collection which contains only the list
elements that are descendants of item II.
The last sentence is particularly interesting: it seems to imply that the jQuery object passed to find() is filtered in order to match the descendants of the elements in the original set. If that's indeed the case, the logic would be inverted, and the previous element set would end up being $allListElements instead of the set returned by find().
A look at the jQuery source code shows that's exactly what happens:
find: function(selector) {
var self = this, i, l;
if (typeof selector !== "string") {
return jQuery(selector).filter(function() {
for (i = 0, l = self.length; i < l; i++) {
if (jQuery.contains(self[i], this)) {
return true;
}
}
});
}
// [...]
}
So, when you write:
var elements = $("p").find($("*")).andSelf();
You're actually writing the equivalent of:
var self = $("p"), i, l;
var elements = $("*").filter(function() {
for (i = 0, l = self.length; i < l; i++) {
if ($.contains(self[i], this)) {
return true;
}
}
}).andSelf();
As you can see, the previous element set is actually $("*") instead of the set returned by find($("*")) because of the logic inversion. Therefore, all the elements in the document end up being legitimately added to the current set by andSelf().
You just need
$("p").css("background-color","blue");
To change the color or all the p tags in the document. Is there some specific reason for the way you have done it?
The $("*") has no context, so it selects every element in the document. You want to find all elements within the currently selected element, so you need to just pass the string to find.
However, it's completely unnecessary and you could just apply the style to the p (as the span is a child you don't to apply it to that too):
$("p").css("background-color","blue");
Note that in that line above I've used background-color with no spaces, unlike in your question. I'm guessing it was just a typo when you wrote the question, but it won't work if you put spaces in the property name.
You don't have to do any of that. Just do this.
$(function() { $("p").css('background-color', 'blue'); });
Note: $(function() {}); is the same as $(document).ready(function(){});
Edit: Since you have two, you may have to do this:
$(function() { $("p").each(item, function() { item.css('backround-color', 'blue'); })});
Edit2: Based on your comments, you want this:
$(function() { $("p").find('span').andSelf().css('background-color', 'blue'); });
The difference between $("p").find(" * ") and $("p").find($(" * ")) is that in the second one you're passing find() a jquery object instead of a regular selector string.
EDIT: I just tried it out. Looks like adding the andSelf() makes it select the entire document somehow. The logical process would be select p > find all elems inside that match everything in the document > select self(p) > color, but it seems to be going wrong at the select self bit.
I think it(the andSelf()) just selects the object passed to find(), which is $('*'), and so selects everything.
If you want to select all P's simply use
$(document).ready(function(){
$("p").css("background-color","blue");
});
No reason to complicate stuff
If you want to select the spans inside you can do something like
$(document).ready(function(){
$("p > span").css("background-color","blue");
});
** Update **
Your selector attribute in your find query is bad, you shouldn't have it like $("*") but only "*". However the $("p").find("*")... will only select any elements inside the <p> tag so trailing the find method with an andSelf will make the selection ambiguous.