JavaScript DOM: Find Element Index In Container
JavascriptHtmlDomParent ChildJavascript Problem Overview
I need to find an index of element inside its container by object reference. Strangely, I cannot find an easy way. No jQuery please - only DOM.
UL
LI
LI
LI - my index is 2
LI
Yes, I could assign IDs to each element and loop through all nodes to match the ID but it seems a bad solution. Isn't there something nicer?
So, say I have an object reference to the third LI as in the example above. How do I know it is index 2?
Thanks.
Javascript Solutions
Solution 1 - Javascript
You could make usage of Array.prototype.indexOf
. For that, we need to somewhat "cast" the HTMLNodeCollection
into a true Array
. For instance:
var nodes = Array.prototype.slice.call( document.getElementById('list').children );
Then we could just call:
nodes.indexOf( liNodeReference );
Example:
<ul id="list">
<li>foo</li>
<li class="match">bar</li>
<li>baz</li>
</ul>
var nodes = Array.prototype.slice.call( document.getElementById('list').children ),
liRef = document.getElementsByClassName('match')[0];
console.log( nodes.indexOf( liRef ) );
Solution 2 - Javascript
Here is how I do (2018 version ?) :
const index = [...el.parentElement.children].indexOf(el);
Tadaaaam. And, if ever you want to consider raw text nodes too, you can do this instead :
const index = [...el.parentElement.childNodes].indexOf(el);
I spread the children into an array as they are an HTMLCollection (thus they do not work with indexOf).
Be careful that you are using Babel or that browser coverage is sufficient for what you need to achieve (thinkings about the spread operator which is basically an Array.from behind the scene).
Solution 3 - Javascript
2017 update
The original answer below assumes that the OP wants to include non-empty text node and other node types as well as elements. It doesn't seem clear to me now from the question whether this is a valid assumption.
Assuming instead you just want the element index, previousElementSibling
is now well-supported (which was not the case in 2012) and is the obvious choice now. The following (which is the same as some other answers here) will work in everything major except IE <= 8.
function getElementIndex(node) {
var index = 0;
while ( (node = node.previousElementSibling) ) {
index++;
}
return index;
}
Original answer
Just use previousSibling
until you hit null
. I'm assuming you want to ignore white space-only text nodes; if you want to filter other nodes then adjust accordingly.
function getNodeIndex(node) {
var index = 0;
while ( (node = node.previousSibling) ) {
if (node.nodeType != 3 || !/^\s*$/.test(node.data)) {
index++;
}
}
return index;
}
Solution 4 - Javascript
Array.prototype.indexOf.call(this.parentElement.children, this);
Or use let
statement.
Solution 5 - Javascript
For just elements this can be used to find the index of an element amongst it's sibling elements:
function getElIndex(el) {
for (var i = 0; el = el.previousElementSibling; i++);
return i;
}
Note that previousElementSibling
isn't supported in IE<9.
Solution 6 - Javascript
You can use this to find the index of an element:
Array.prototype.indexOf.call(yourUl, yourLi)
This for example logs all indices:
var lis = yourList.getElementsByTagName('li');
for(var i = 0; i < lis.length; i++) {
console.log(Array.prototype.indexOf.call(lis, lis[i]));
}
Solution 7 - Javascript
A modern native approach could make use of 'Array.from()' - for example: `
const el = document.getElementById('get-this-index')
const index = Array.from(document.querySelectorAll('li')).indexOf(el)
document.querySelector('h2').textContent = `index = ${index}`
<ul>
<li>zero
<li>one
<li id='get-this-index'>two
<li>three
</ul>
<h2></h2>
`
Solution 8 - Javascript
An example of making an array from HTMLCollection
<ul id="myList">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var tagList = [];
var ulList = document.getElementById("myList");
var tags = ulList.getElementsByTagName("li");
//Dump elements into Array
while( tagList.length != tags.length){
tagList.push(tags[tagList.length])
};
tagList.forEach(function(item){
item.addEventListener("click", function (event){
console.log(tagList.indexOf( event.target || event.srcElement));
});
});
</script>
Solution 9 - Javascript
You can iterate through the <li>
s in the <ul>
and stop when you find the right one.
function getIndex(li) {
var lis = li.parentNode.getElementsByTagName('li');
for (var i = 0, len = lis.length; i < len; i++) {
if (li === lis[i]) {
return i;
}
}
}
Solution 10 - Javascript
If you want to write this compactly all you need is:
var i = 0;
for (;yourElement.parentNode[i]!==yourElement;i++){}
indexOfYourElement = i;
We just cycle through the elements in the parent node, stopping when we find your element.
You can also easily do:
for (;yourElement.parentNode.getElementsByTagName("li")[i]!==yourElement;i++){}
if that's all you want to look through.
Solution 11 - Javascript
const nodes = Array.prototype.slice.call( el.parentNode.childNodes );
const index = nodes.indexOf(el);
console.log('index = ', index);
Solution 12 - Javascript
Another example just using a basic loop and index check
HTML
<ul id="foo">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
JavaScript runs onload/ready or after ul is rendered
var list = document.getElementById("foo"),
items = list.getElementsByTagName("li");
list.onclick = function(e) {
var evt = e || window.event,
src = evt.target || evt.srcElement;
var myIndex = findIndex(src);
alert(myIndex);
};
function findIndex( elem ) {
var i, len = items.length;
for(i=0; i<len; i++) {
if (items[i]===elem) {
return i;
}
}
return -1;
}
Running Example
Solution 13 - Javascript
Just pass the object reference to the following function and you will get the index
function thisindex(elm)
{
var the_li = elm;
var the_ul = elm.parentNode;
var li_list = the_ul.childNodes;
var count = 0; // Tracks the index of LI nodes
// Step through all the child nodes of the UL
for( var i = 0; i < li_list.length; i++ )
{
var node = li_list.item(i);
if( node )
{
// Check to see if the node is a LI
if( node.nodeName == "LI" )
{
// Increment the count of LI nodes
count++;
// Check to see if this node is the one passed in
if( the_li == node )
{
// If so, alert the current count
alert(count-1);
}
}
}
}
}