35

I need to know the index of clicked element. Can't figure out how to do it

for (i = 0; i < document.getElementById('my_div').children.length; i++) {
    document.getElementById('my_div').children[i].onclick = function(){'ALERT POSITION OF CLICKED CHILD'};
}

this.index?

here is a example of what I am trying to do (it only gives back 6):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Untitled Document</title>
<style type="text/css">
body{margin:0;}
#container div{height:50px;line-height:50px; text-align:center}
</style>
</head>
<body>
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
<script>
for (i = 0; i < document.getElementById('container').children.length; i++) {
    document.getElementById('container').children[i].onclick = function(){alert('Number ' + i + ' was clicked')};
}
</script>
</body>
</html>
1

10 Answers 10

61

With ES6 destructuring you can do

const index = [...el.parentElement.children].indexOf(el)

or

const index = Array.from(el.parentElement.children).indexOf(el)

or ES5 version

var index = Array.prototype.slice.call(el.parentElement.children).indexOf(el)
Sign up to request clarification or add additional context in comments.

Comments

44

Here is a piece of code that can help you get the index of the clicked element inside the for loop. All you need is a new scope:

var g = document.getElementById('my_div');
for (var i = 0, len = g.children.length; i < len; i++)
{

    (function(index){
        g.children[i].onclick = function(){
              alert(index)  ;
        }    
    })(i);

}

Edit 1: Incorporating user Felix Kling's comments into the answer.

event handler already is a closure

Edit 2: Updated fiddle link

5 Comments

Strictly speaking the event handler already is a closure. What the OP needed was a new scope.
Any idea why the code may be failing to show any output? I tried both Safari and Google.
@rohan-patel That is odd. Here is a newer fiddle: jsfiddle.net/gffwse8q (tested in Chrome and Safari).
Thanks for the update! Not sure why it was broken. Maybe version change?
See my second answer on this page, this solution is far for optimal. stackoverflow.com/questions/8801787/…
7

The accepted answer (from Ashwin Krishnamurthy) is actually far from optimal.

You can just do:

const g = document.getElementById('my_div');
for (let i = 0, len = g.children.length; i < len; i++)
{
    g.children[i].onclick = function(){
        alert(index)  ;
    }
}

to avoid creating unnecessary closures. And even then it's not optimal since you're creating 6 DOM event handlers (6 divs in the example above) just to get a number of a single clicked div.

What you should actually do is use an event delegation (attach single click event to the parent) and then check the e.target's index using the method I've mentioned earlier and above (Get index of clicked element using pure javascript).

3 Comments

Not sure why this has -1 since it's better solution than any mentioned here ;)
it just doesn't work. have you even tried running it?
At present I think this is the best answer. Since we have the option to use 'let' to keep 'i' local in scope, in this case it's superior to 'var' and we don't need to write the anon self invoking function to define our own local variable. Just change it to 'alert(i)' not alert(index) since index is not defined in your code @MelkorNemesis
5

I had the same issue where I needed to loop through an array and get the index number of the item clicked.

Here is how I solved the issue...

//first store array in a variable
let container = [...document.getElementById('container')];

//loop through array with forEach function
container.forEach((item,index) => {
    item.addEventListener('click', () => console.log(index));
});

This will console.log the index number of the item clicked on.

Hope this answers some questions.

1 Comment

When you are using a forEach, you don't need to do container.indexOf. Just change your forEach(item => { syntax to forEach((item, index) => { and you have the index !!
5

I made a function to find the index.

function getElementIndex(el) {
  return [...el.parentElement.children].indexOf(el);
}

Call it like this:

const index = getElementIndex(element);

Comments

2

Table cell elements have a cellIndex property, but I don't know about other elements. You will either have to

  • create a closure to reserve the value of i
  • dynamically count previousSiblings
  • add an index property in your for-loop and read that (don't augment host objects).

The closure approach will be the easiest, I think. Please make sure you have understood how closures work, there are good explanations on the web.

function makeAlertNumber(element, i) {
    element.addEventListener('click', function() {
       alert('Number ' + i + ' was clicked');
    }, false);
}
[].slice.call(document.getElementById('container').children).forEach(makeAlertNumber); // homework: find a way to express this for older browsers :-)

1 Comment

THanks Bergi, would you like to show an example in the code I added?
1

The index in relationship to what ?

If it is about the index within the current HTML collection, the index would just be represented with your i counter variable.

One word of caution: Since HTMLCollections are "Live", you should ever use them to figure out the .length within a loop. If it happens to be that those elements are added or removed within the loop, strange and dangerous things can happen. Cache the .length value before calling the loop instead.

3 Comments

@david: indeed. Totally forgot about this fact :)
Thanks jAndy. The index related to the other children. Added a example if you want to have a look
You could also simply loop over the elements in reverse order
1
for (let i = 0; i < childNodes.length; i++){
      (function(index){
        childNodes[i].addEventListener("click", myScript);
        function myScript(){
          console.log(index);
        }
      })(i);
    }

1 Comment

If you are using let, you don’t need the IIFE.
0

getIndexOfNode: function(node){ var i = 1; while(node.previousElementSibling != null){ i++ } return i; }
the function will return the index of the node passed in its parent element.

1 Comment

node never changes, so this is an infinite loop.
0
getIndexOfNode = function(node){
    var i = 1;
    while(node.previousElementSibling != null){
      node = node.previousElementSibling;
        i++
    }
    return i;
} 

1 Comment

While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. You can find more information on how to write good answers in the help center: stackoverflow.com/help/how-to-answer . Good luck 🙂

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.