1

I have a list of elements stored in a variable called elementList, and want to add an event listener to each of them. So I created the following loop:

for (i = 0; i < elementList.length; i++) {
  elementList[i].addEventListener('click', myFunction, false);
}

The problem? I need to pass on i as a parameter to myFunction. After doing some research online, I found this solution:

for (i = 0; i < elementList.length; i++) {
  elementList[i].addEventListener('click', (function(i){
    return function(){
      myFunction(i);
    };
  }(i)), false);
}

The code works nicely – but there's still a problem. Later on in my code, I need to remove the event listener again, which is done with the removeEventListener() method, as I found out after some more research.

But this method requires a named, external function – it doesn't work for anonymous functions. So it would work for my first example above, but not for the second.

So my question is: how do I add an event listener to a list of elements, which allows me to do both of these things:

  1. Pass parameters to my function
  2. Remove the event listener again, later in the code

Thanks for your help!

Run_Script
  • 2,487
  • 2
  • 15
  • 30
  • Does this answer your question? [How to pass arguments to addEventListener listener function?](https://stackoverflow.com/questions/256754/how-to-pass-arguments-to-addeventlistener-listener-function) – Emiel Zuurbier Mar 31 '20 at 19:03
  • @EmielZuurbier I'm not sure. I know how to pass arguments in an `addEventListener` function, I just don't know how to do it in a way that can be removed again later. Does the question you have provided a link to answer this second point as well? – Run_Script Apr 03 '20 at 19:55

2 Answers2

2

You can generate a list of functions and use them to remove the listener:

let removers = elementList.map((el, idx) => {
  let handler = () => myFunction(idx);
  el.addEventListener('click', handler);
  return () => el.removeEventListener('click', handler);
});

// when you need
//
removers[4]();  // calls removeEventListener
TheGr8_Nik
  • 3,080
  • 4
  • 18
  • 33
1

To remove the event listener from the button, you'll need to have a reference to the function itself. So before using addEventListener store the function in an object or an array, or something where you can look back and find this function. Because removeEventListener won't work if you don't give it the exact same function as you used with addEventListener.

Down below in the code snippet I've constructed an example of a way to store these event listeners and call it an EventCollection. This class functions as a container and holds a list of every event that you want to add. This way you can add or remove all the event listeners you want anytime in your code, without having to do too much work.

class EventCollection {

  /**
   * Create a list to store the entries in.
   */
  constructor() {
    this.entries = [];
    this.isListening = false;
  }

  /**
   * Add an entry to the collection to listen for on an event.
   */
  append(target, type, listener, options = false) {
    if (!(target instanceof EventTarget)) return;
    this.entries.push({ target, type, listener, options });
    return this;
  }

  /**
   * Listen for all the entries in the list.
   */
  listen() {
    if (!this.isListening) {
      this.entries.forEach(({ target, type, listener, options }) => {
        target.addEventListener(type, listener, options);
      });
      this.isListening = true;
    }
    return this;
  }

  /**
   * Stop listening for all the entries in the list.
   */
  stopListening() {
    this.entries.forEach(({ target, type, listener, options }) => {
      target.removeEventListener(type, listener, options);
    });
    this.isListening = false;
    return this;
  } 

}

// Create a new instance of an EventCollection
var eventCollection = new EventCollection();

var buttons = document.getElementsByTagName('button');

function myFunction(index) {
  alert(index);
}

// Add all the event listeners to the collection.
for (var i = 0; i < buttons.length; i++) {
  (function(i){
    eventCollection.append(buttons[i], 'click', function() {
      myFunction(i);
    }, false);
  }(i));
}

// Start listening.
eventCollection.listen();

// After 5 seconds, stop listening.
// The buttons won't work anymore.
setTimeout(function() {
  eventCollection.stopListening();
}, 5000);
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>

Building the collection works like this. With the new keyword.

// Create a new collection
var eventCollection = new EventCollection();

The next step is to add the event that you want to listen to. It needs the element, the type of event and the function to call when the event is triggered.

eventCollection.append(element, 'click', function() {});

Now your events are in the collection and stored, but they are not yet listening to the events. Use the .listen() method to loop over all the events in the collection and listen for them.

eventCollection.listen();

And whenever you want to stop listening to events in your collection, then use the following.

eventCollection.stopListening();
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32