0

I'm trying to build a script that detects the particular <span> the user clicks on and outputs the value of the contents of that clicked span.

My HTML looks like this:

<div id="span-container">
    <span>Lorem</span>
    <span>Ipsum</span>
    <span>Something...</span>
    <span>Something...</span>
    <span>Amet</span>
</div>

And my Javascript looks like this:

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    spans[i].onclick = function() {
        alert(spans[i].innerHTML);
    }
}

Attempting to run this code results in a Cannot read property 'innerHTML' of undefined error.

I'm sure giving each span an ID that correlates to its contents like <span id="lorem">Lorem</span> would work, but I'm optimistic that a more elegant solution exists.

I'd also like to avoid using jQuery if possible. Thanks!

4 Answers4

2

Use event delegation:

var div = document.getElementById('span-container');
div.addEventListener('click', function(e) {
    var target = e.target;
    if(target.nodeName == 'SPAN') {
        alert(target.innerHTML);
    }
});
Edwin Reynoso
  • 1,511
  • 9
  • 18
  • 2
    Upvoting it since this solution tries to optimize the number of action handlers. Event delegation is always better performant and flexible (No need to put one more action handler if one more span element is added). – Diptendu May 29 '15 at 05:14
1

Wrapping it

The problem is, i has changed by the time the user click on it. Use a self-executing function or eventListener

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    (function (j) {
        spans[j].onclick = function() {
            alert(spans[j].innerHTML);
        }
    }(i));
}

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    (function (j) { // Receives as j
        spans[j].onclick = function() {
            alert(spans[j].innerHTML);
        }
    }(i)); // Passes in i
}
<div id="span-container">
    <span>Lorem</span>
    <span>Ipsum</span>
    <span>Something...</span>
    <span>Something...</span>
    <span>Amet</span>
</div>


Using this

this will refer to the element clicked and is probably the best way to do this:

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    spans[i].onclick = function() {
        alert(this.innerHTML);
    }
}

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    spans[i].onclick = function() {
        alert(this.innerHTML);
    }
}
<div id="span-container">
    <span>Lorem</span>
    <span>Ipsum</span>
    <span>Something...</span>
    <span>Something...</span>
    <span>Amet</span>
</div>
Downgoat
  • 13,771
  • 5
  • 46
  • 69
0

The problem here is the wrong use of a closure variable in a loop

But I think in this case you can use addEventListener

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

function spanClickHandler() {
  alert(this.innerHTML);
}

for (var i = 0; i < spans.length; i++) {
  spans[i].addEventListener('click', spanClickHandler, false);
}
<div id="span-container"> <span>Lorem</span>
  <span>Ipsum</span>
  <span>Something...</span>
  <span>Something...</span>
  <span>Amet</span>

</div>

or just use this.innerHTML as this inside the event handler refers to the span element

spans[i].onclick = function () {
    alert(this.innerHTML);
}
Community
  • 1
  • 1
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • Using `.onclick` isn't the problem and `addEventListener` isn't the solution. It's using the `this` keyword to refer to the element clicked. I feel that you are emphasizing on the wrong topic – Downgoat May 29 '15 at 04:02
  • @vihan1086 the addEventListner is used because having an anonymous function in a loop is not a good practice... though you can use the named function `onclick`... also the using `this` in the `onclick` is already added as a solution... Using `addEventListner ` or not is a matter of practice.... – Arun P Johny May 29 '15 at 04:04
0

You can use this for the current element.

Try this code:

div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");

for(var i = 0; i < spans.length; i++) {
    spans[i].onclick = function() {
        alert(this.innerHTML);
    }
}
juntapao
  • 407
  • 3
  • 12