Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

addEventListener, for(), index. how to use closure? [duplicate]

I have this code:

var items = this.llistat.getElementsByTagName('a');

for( var i = 0; i < items.length; i++ ){    
  items[i].addEventListener('click', function(event) {
    alert( i );
  }, items[i]);
}

where the event is listened, but there are 3 items and the alert allways print 3 on any of the elements (it doesn't respect the index),

Dosen't items[i] shouldn't do the job as closure?

thanks!

like image 369
Toni Michel Caubet Avatar asked Dec 14 '13 20:12

Toni Michel Caubet


2 Answers

No, the third argument of addEventListener is the useCapture one. See MDN for more information.

But you can use:

for( var i = 0; i < items.length; i++ ){
    (function(i){
        items[i].addEventListener('click', function(event) {
            alert( i );
        }, false);
    })(i);
}

or

var handler = function(event) {
    var i = items.indexOf(this);
    alert( i );
};
for( var i = 0; i < items.length; i++ ){
    items[i].addEventListener('click', handler, false);
}

The first one creates a new event handler for each element, so it needs more memory. The second one reuses the same event listener, but uses indexOf, so it's more slow.

like image 122
Oriol Avatar answered Oct 03 '22 01:10

Oriol


That's a classical closure issue : you must create a new function bound, not to the 'i' variable, but to its value at the time of binding :

var items = this.llistat.getElementsByTagName('a');

for( var i = 0; i < items.length; i++ ) {
        items[i].addEventListener('click', listener.bind( null, i) );
}

function listener(index) {
         alert(index);
}
like image 32
GameAlchemist Avatar answered Oct 03 '22 00:10

GameAlchemist