1

so I'm having a bit of an issue. So, I want to loop through an array of SVG objects and add an event listener to each object.

My issue is that when I try to do this with this line:

alert(myRects[i].id + ' success! '+ i);

I get an error saying id is undefined...

And then when I try it with this line... (the one in the code below):

 alert(rectInstance.id + ' success! '+ i);

...it seems as if every object has the same event listener as the last object in the array. Idk if my thinking is completely off or if I'm misusing something...

As always, any help is really appreciated

var myRects;
var rectInstance;

// event listener to make sure the page has loaded before running the scrupt
window.addEventListener("load", function() {
// gets an SVG object from the inline HTML
var svgObject = document.getElementById('rectTestSvg').contentDocument;


myRects = Array.from(svgObject.querySelectorAll("rect"));



// loop through the rects array
for(var i = 0; i < myRects.length; i++)
{
    // copy myRects array to a temporary object
    var rectInstance = myRects[i];
    //add an on click event listener to each object in the rects array
     rectInstance.addEventListener('click', function(){
        //pop up that proves each rect got a unique on click event
        alert(rectInstance.id + ' success! '+ i);

    })
    // add object now with eventlistener back to myRects array
    myRects[i] = rectInstance;

  }


});
Mehdi Nellen
  • 8,486
  • 4
  • 33
  • 48
Ravajava
  • 55
  • 1
  • 5
  • You have a scope issue, if your using new ES features, just change your `var` to a `let / const`.. – Keith Jun 20 '18 at 23:26
  • Do the `rect` elements inside the svg elements have an `id` ? This might explain why it is undefined. For the scope issue, either use `let` or encase the function inside an `IIFE` which will contain the context to each iteration – Sushanth -- Jun 20 '18 at 23:29
  • Yeah, the rect elements have an ID. But using an IIFE worked, so all is well. – Ravajava Jun 20 '18 at 23:50

1 Answers1

0

To fix the scoping issue, you have 2 approaches to solve it

If using ES6, replace var with let.

Otherwise enclose the callback in an IIFE which will create a new function scope.

rectInstance.addEventListener('click', (function(newI) {
    return function() {
       //pop up that proves each rect got a unique on click event
       alert(rectInstance.id + ' success! ' + newI);
    }
})(i));
Sushanth --
  • 55,259
  • 9
  • 66
  • 105
  • Thanks a lot, helped put me on the right track. Really had never encountered the concept of an IIFE up to now. Just for posterity, I did have to make a small change to make this work: `alert(myRects[newI].id + ' success! ' + newI);` So, rectInstance isn't needed anymore, which looks way nicer anyways. – Ravajava Jun 20 '18 at 23:49