Search code examples
javascriptarraysdom-eventstypeerroraddeventlistener

How can I make a style event with addEventListener to multiple Nodes


I am trying to set a style event for a multiple images tags and I can't: the error is in the anonymous function of the event when I put into a loop to make the effect individually and for all galleries in the document with images[i].

Why ? : Uncaught TypeError: Cannot set property 'style' of undefined at HTMLImageElement.<anonymous>

images = document.querySelectorAll(".gallery img");

for (var i=0; i<images.length; i++){
    images[i].addEventListener('mouseout', function(){ images[i].style=" transform: scale(.8)" }); 
    images[i].addEventListener('mouseover', function(){ images[i].style=" transform: scale(1.2)" }); 
} 
<div class="gallery">
    <img src="https://picsum.photos/300/180">
    <img src="https://picsum.photos/300/180">
    <img src="https://picsum.photos/300/180">
</div>


Solution

  • ES6+ solution:

    Simply change var to let in the for loop.

    images = document.querySelectorAll(".gallery img");
    
    for (let i = 0; i < images.length; i++){
        images[i].addEventListener('mouseout', function(){ images[i].style=" transform: scale(.8)" }); 
        images[i].addEventListener('mouseover', function(){ images[i].style=" transform: scale(1.2)" }); 
    } 
    <div class="gallery">
        <img src="https://picsum.photos/300/180">
        <img src="https://picsum.photos/300/180">
        <img src="https://picsum.photos/300/180">
      </div>

    If you must use var rather than let, you can use .bind() to set the value of i for the function. Otherwise it will reference the last value of i in the loop because of the async nature of the event callback and the higher scope of i due to the use of var.

    images = document.querySelectorAll(".gallery img");
    
    function callback1(i){ images[i].style=" transform: scale(.8)" };
    function callback2(i){images[i].style=" transform: scale(1.2)" };
    
    for (var i=0; i<images.length; i++){
        images[i].addEventListener('mouseout', callback1.bind(this, i));
        images[i].addEventListener('mouseover', callback2.bind(this, i)); 
    }
      <div class="gallery">
        <img src="https://picsum.photos/300/180">
        <img src="https://picsum.photos/300/180">
        <img src="https://picsum.photos/300/180">
      </div>