0

I am trying to modify an element when it gets hovered, at some point, I need to get all elements with class name "image", my issue is that while allElements has a value inside of the main function (the first alert shows the value), allElements doesn't have a value anymore when called from the anonymous function (it is undefined).

What's wrong here ?

function register() {

    var i = 0
    var allElements = document.getElementsByClassName("image")
    alert(allElements) // Has a value
    while (i < allElements.length) {
        allElements[i].addEventListener("mouseover", function() {
            var description = null
            var j = 0
            alert(allElements[i]) // Undefined
            while (j < allElements[i].children.length) {
                var child = allElements[i].children[j]
                description = child
                if (child.id == "description") {
                    break
                }
                j++;
            }

            description.style = "display: block"

        });
        i++
    }

}

Thank you

rpadovani
  • 7,101
  • 2
  • 31
  • 50
Pop Flamingo
  • 3,023
  • 2
  • 26
  • 64
  • 2
    In the function in your event listener, you're referring to `allElements[i]`, which is no longer a valid reference. Replace it with `this` – Chris Forrence May 03 '17 at 20:28
  • try referencing it as `alert(this)` rather than the variable outside of the event listener – scrappedcola May 03 '17 at 20:29
  • @ChrisForrence Do you mean `this.allElements[i]` ? – Pop Flamingo May 03 '17 at 20:29
  • To expand on why it's undefined, when the `while` loop finishes, `i` has a value of `allElements.length` (since it increases by 1 on every tick of the loop, even before we exit). If there are 7 elements in `allElements`, then `i` will be 7, and `allElements[7]` does not exist. This is just for your conceptual understanding, follow the suggestions above for the actual fix. – aaronofleonard May 03 '17 at 20:31
  • @Amleonard But what is `this` referring to ? – Pop Flamingo May 03 '17 at 20:31
  • @Amleonard How can `this` be equivalent to alert(allElements) ? – Pop Flamingo May 03 '17 at 20:32
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Heretic Monkey May 03 '17 at 20:33
  • I know it's semi-confusing because it happens behind the scenes, but the javascript engine binds the callback function to the *context* of the element that is listening to the event. The context is basically just what the value of `this` is inside the function. So when calling `allElements[i].addEventListener("mouseover", function() {`, the `addEventListener` function internally binds the callback function to have `this` equal to the element that is calling it. – aaronofleonard May 03 '17 at 20:35
  • @TrevörAnneDenise You should use `this` keyword to access element value in your addEventListener. `this` it refers to an object; that is, the subject in context, or the subject of the executing code. – Junius May 03 '17 at 20:35
  • @Amleonard Oh I see, that's counterintuitive indeed... thank you for your explanation. – Pop Flamingo May 03 '17 at 20:35
  • Just my 2c: what you're doing in js is much easier done with CSS, besides you seem to be looking for multiple child elements with an `id = "description"` attribute, you should use a CSS class instead. E.g.: `.image .description { display: none; } .image:hover .description { display: block }` - crossbrowser and works without js enabled – mfeineis May 03 '17 at 20:39

2 Answers2

0

By the time the event fires, i is equal to elements.length, so elements[i] is undefined - there is no such element as elements[elements.length].

You'll want to read here: JavaScript closure inside loops – simple practical example which explains the loop index variable issue in more detail.

For your specific issue, folks are recommending via comments to use this, because in the event handler the this object refers to the element that has been moused over, which allows you to avoid the loop index issue altogether.

Community
  • 1
  • 1
alexanderbird
  • 3,847
  • 1
  • 26
  • 35
0

Try to pass the event inside the function and access the element through the event.

allElements[i].addEventListener("mouseover", function(e) {
  // code
  alert(e.target);
  // code
});
quirimmo
  • 9,800
  • 3
  • 30
  • 45