0

I have div element "y" and a class of images called "terrain". The below code is intended such that whenever an element of the class is clicked, y and that element share top and left positions.
However, it doesn't seem to be working. What is the solution?

var lands = document.getElementsByClassName("terrain");
for(var i = 0; i < lands.length; i++){
    lands[i].onclick = function(){
        y.style.left = lands[i].offsetLeft;
        y.style.top = lands[i].offsetTop;
    };
}
someGuy
  • 147
  • 1
  • 1
  • 6

2 Answers2

0

You have to use an IIFE so that the currentely iterated "terrain" sets its properties (offsetLeft, offsetTop) to y, when its clicked.

Hope this helps:

var lands = document.getElementsByClassName('terrain');
for (var i = 0; i < lands.length; i++) {
  (function (land) {
    land.onclick = function () {
      alert('left: '+land.offsetLeft+' top: '+land.offsetTop);
      y.style.left = land.offsetLeft + 'px';
      y.style.top = land.offsetTop + 'px';
    };
  }) (lands[i]);
}
Community
  • 1
  • 1
Blauharley
  • 4,186
  • 6
  • 28
  • 47
0

The for loop messes up the closure you have (the varaible i inside the click handler will have the same value for all the lands when one of them is clicked, the value of i will be lands.length which is an undefined value). That's happening because the scope of for remain the same untill the end. You need something that creates a different scope for each item of the lands array. forEach can acheive that like this:

var lands = document.getElementsByClassName("terrain");
Array.prototype.forEach.call(lands, function(land) {
    land.onclick = function(){
        y.style.left = land.offsetLeft;
        y.style.top = land.offsetTop;
    };
});

Since lands (the result of getElementsByClassName) is an array-like object but not an array, forEach is not defined, so we have to call it like this: Array.prototype.forEach.call. Read more about: forEach, closure and call.

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73