Vad
Vad

Reputation: 3740

JavaScript DOM: Find Element Index In Container

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.

Upvotes: 111

Views: 196960

Answers (13)

calipoop
calipoop

Reputation: 832

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>

Upvotes: 8

Nguyen Anh Vu
Nguyen Anh Vu

Reputation: 121

    const nodes = Array.prototype.slice.call( el.parentNode.childNodes );
    const index = nodes.indexOf(el);
    console.log('index = ', index);

Upvotes: 5

Julien BONNIN
Julien BONNIN

Reputation: 1020

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).

Upvotes: 102

gen_Eric
gen_Eric

Reputation: 227180

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

}

Demo

Upvotes: 1

jAndy
jAndy

Reputation: 235962

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:

var nodes = Array.prototype.slice.call( document.getElementById('list').children ),
    liRef = document.getElementsByClassName('match')[0];

console.log( nodes.indexOf( liRef ) );
<ul id="list">
    <li>foo</li>
    <li class="match">bar</li>
    <li>baz</li>    
</ul>

Upvotes: 120

Tim Down
Tim Down

Reputation: 324477

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

Upvotes: 54

Ada
Ada

Reputation: 11

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.

Upvotes: 1

WayHunter
WayHunter

Reputation: 1225

Array.prototype.indexOf.call(this.parentElement.children, this);

Or use let statement.

Upvotes: 27

berandomsen
berandomsen

Reputation: 21

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>

Upvotes: 2

Web_Designer
Web_Designer

Reputation: 74520

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.

Upvotes: 10

Clyde Lobo
Clyde Lobo

Reputation: 9174

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

Upvotes: 0

epascarello
epascarello

Reputation: 207491

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

jsFiddle

Upvotes: 0

user657496
user657496

Reputation:

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

JSFIDDLE

Upvotes: 11

Related Questions