Event listeners and closures on HTML collection in for loop

517 Views Asked by At

The code is

//Logic which works when the desired element is clicked
function changeArtistPhotoAndBio(prop) {
    var artistPhoto = document.getElementsByClassName("artist-photo")[0];
    var artistBio = document.getElementsByClassName("artist-bio")[0];

    var i = prop.getAttribute("src").indexOf(".jpg");
    var photoName = prop.getAttribute("src").slice (0, i);

    artistPhoto.style.background="url(" + photoName + "-large.jpg";
    console.log("it happened");
};

//Setting listeners for the click event in the loop
var artists = document.getElementsByClassName("gallery")[0].getElementsByTagName("img");
for (var i = 0; i < artists.length; i++) {
    artists[i].addEventListener("click", changeArtistPhotoAndBio(artists[i]));
}

And the console output is

7x it happened

And the event handler for the click function does not work. I've tried isolating handler in the closure, like this:

for (var i = 0; i < artists.length; i++) {(function(i) {
    artists[i].addEventListener("click", changeArtistPhotoAndBio(artists[i]));
}(i))
}

but the output is still the same. So there are two questions:

1) Why does the console output contain results of seven handler invocations if I did not invoke the function, just set it as a handler?

2) How can I set handlers in the "for" loop for HTML collection?

2

There are 2 best solutions below

0
On

You have to use closures:

var artists = document.getElementsByClassName("gallery")[0].getElementsByTagName("img");
for (var i = 0; i < artists.length; i++) {
    artists[i].addEventListener("click", function(index) {
        return function() {
            //You can use index for the current clicked item index
            // console.log(index);
            var artistPhoto = document.getElementsByClassName("artist-photo")[0];
            var artistBio = document.getElementsByClassName("artist-bio")[0];

            var i = this.getAttribute("src").indexOf(".jpg");
            var photoName = this.getAttribute("src").slice (0, i);

            artistPhoto.style.background="url(" + photoName + "-large.jpg";
            console.log("it happened");

        }
    }(i));
}
0
On
$('body *').on('mouseover',function(){console.log(this.tagName)});

$('body *') selects all elements within the body.