-1

When click on an image created from an array, both of onclick and addEventListener('click',function(){}) don't work.

I am trying to display geojson data on Google map api. With javascript, I have stored the data into an array and displayed each item successfully on Google map. The images should be clickable and display more information when clicked.

for (var i = 0; i < arrItems.length; i++) {
    var image = arrItems[i].properties.image;

    //create image(list_img)
    var list_img = document.createElement("img");
    list_img.className = "list_img card-img-top";
    list_img.src = arrItems[i].properties.image; 

    list_img.onclick = alert(i);
    list_img.addEventListener("click",function(){
        console.log(i);
    });
}

In the code above, if I use onclick, it alerts all the id number before the page is loaded. And no response when I click the images after the page loaded. if I user addEventListener, no matter which image clicked, it always outputs the last i number.

alexandercannon
  • 544
  • 5
  • 24
Jing Fan
  • 63
  • 5
  • list_img.onclick = alert(i); <-- well you are calling alert and assigning what it returns to the click event listener. – epascarello Aug 27 '19 at 12:38
  • Onclick should be a function. – geocodezip Aug 27 '19 at 12:39
  • `list_img.onclick = function () { alert(i); };` –  Aug 27 '19 at 12:39
  • @ChrisG and that is now a different problem. They are all going to alert the same value. – epascarello Aug 27 '19 at 12:40
  • @epascarello You're referring to using `let i` instead? –  Aug 27 '19 at 12:40
  • Possible duplicate of [addEventListener calls the function without me even asking it to](https://stackoverflow.com/questions/16310423/addeventlistener-calls-the-function-without-me-even-asking-it-to) –  Aug 27 '19 at 12:43
  • N.B. can use a IIFE to bind the context of _i_ if you don't have access to _let_ for some reason. `(function(i){ alert(i) })(i)`, otherwise the context of _i_ by the time you click will always be the last value of _i_ from the loop. – alexandercannon Aug 27 '19 at 13:29

2 Answers2

0

Your issue is that you are creating the elements and binding at the same time.

You should create the elements first, then find them in the DOM and finally you can bind the event listeners.

If you do both at the same time then it'll fire the events immediately, and you won't have the proper binding on the elements once they're written.

var container = document.querySelector('.container')

// list of fake items
var arrItems = ['a', 'b', 'c'];

// create your elements and append them to the DOM
arrItems.forEach(e => {
  //create image(list_img)
  var list_img = document.createElement("div");
  list_img.className = "list_img card-img-top";
  list_img.innerHTML = e;
  //append to my example element
  container.append(list_img)
})

// find your new elements in the DOM
var elements = document.querySelectorAll('.list_img');

// finally, append the event listeners
elements.forEach(e => e.addEventListener("click", function(){
    alert('click!');
}));
<div class="container"></div>
alexandercannon
  • 544
  • 5
  • 24
0

We can make your code work using an IIFE (immediately invoked function expression)

for (var i = 0; i < arrItems.length; i++) {
    var image = arrItems[i].properties.image;

    //create image(list_img)
    var list_img = document.createElement("img");
    list_img.className = "list_img card-img-top";
    list_img.src = arrItems[i].properties.image; 

    list_img.onclick = (function(i){
        return function(event){
            console.log(i, event.target)
        }
    })(i)
    list_img.addEventListener("click",(function(i){
        return function(event){
            console.log(i, event.target)
        }
    })(i));
}

This creates a new i, scoped to the current function.

alexandercannon
  • 544
  • 5
  • 24