Search code examples
javascriptaddeventlistenercreatejs

addEventListener (and removeEventListener) function that need param


I need to add some listeners to 8 object (palms). These object are identical but the behaviour have to change basing to their position. I have the follow (ugly) code:

root.palmsStatus = ["B","B","B","B","B","B","B","B"];

if (root.palmsStatus[0] !== "N")
  root.game.palms.palm1.addEventListener("click", palmHandler = function(){ palmShakeHandler(1); });
if (root.palmsStatus[1] !== "N")
  root.game.palms.palm2.addEventListener("click", palmHandler = function(){ palmShakeHandler(2); });
if (root.palmsStatus[2] !== "N")
  root.game.palms.palm3.addEventListener("click", function(){ palmShakeHandler(3); });
if (root.palmsStatus[3] !== "N")
  root.game.palms.palm4.addEventListener("click", function(){ palmShakeHandler(4); });
if (root.palmsStatus[4] !== "N")
  root.game.palms.palm5.addEventListener("click", function(){ palmShakeHandler(5); });
if (root.palmsStatus[5] !== "N")
  root.game.palms.palm6.addEventListener("click", function(){ palmShakeHandler(6); });
if (root.palmsStatus[6] !== "N")
  root.game.palms.palm7.addEventListener("click", function(){ palmShakeHandler(7); });
if (root.palmsStatus[7] !== "N")
  root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); });

I have two needs:

1) doesn't use an anonymous function on click event.

I wrote this code, but it doesn't work

root.game.palms.palm8.addEventListener("click", palmShakeHandler(8));

So this one works fine

root.game.palms.palm8.addEventListener("click", function(){ palmShakeHandler(8); });

But I didn't understand how remove the event listener. I try this solution, but it doesn't work

root.game.palms.palm8.addEventListener("click", palmHandler = function(){ palmShakeHandler(8); });
root.game.palms.palm8.removeEventListener("click", palmHandler);

2) add and remove listener in a for cycle

I wrote the follow code but the behaviour is not correct.

  for (i=1; i <= root.palmsStatus.length; i++){
    if (root.palmsStatus[i-1] !== "N"){
      root.game.palms["palm" + i].addEventListener("click", function(){ palmShakeHandler(i); });
    }
  } 

the listeners was added but the value of the parameter passed to the palmShakeHandler is always 8.

Nobody could help me to fix these issues?


Solution

  • There is a actually, a perfect way to do that in JavaScript using the Function.prototype.bind method.

    bind let you define extra parameters that will be passed, as arguments, of the function.

    You should also keep in mind that bind creates a new function and doesn't modify the initial function.

    Here is what it looks like:

    function palmHandler(number) {
      // your code working with `number`
    }
    
    var palmHandler8 = palmHandler.bind(null, 8)
    // the palmHandler8 is now tied to the value 8.
    // the first argument (here null) define what `this` is bound to in this function
    

    This should fix your problem, and you will be able to remove handlers easily :)

    Your code will look like this:

    for (i=1; i <= root.palmsStatus.length; i++){
      if (root.palmsStatus[i-1] !== "N"){
        root.game.palms["palm" + i].addEventListener("click", palmShakeHandler.bind(null, i));
      }
    } 
    

    To be able to remove the handler afterward, you need to keep a reference to the function you create with bind. This would be the way to do this.

    var boundHandler = handler.bind(null, i);
    element.addEventListener(boundHandler);
    element.removeEventListener(bounderHander);
    

    If you want to know more about the awesome bind method in JavaScript, the MDN is your friend :) https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

    BTW, the problem with you function always returning 8 is a very common question in JavaScript. This thread will explain everything (spoiler, it's a matter of scoping :) ) https://stackoverflow.com/a/750506/2745879