Javier Quevedo
Javier Quevedo

Reputation: 2046

Unable to remove an (bound) event listener

I am a newbie on javascript and I am encountering the following problem, which I wasn't able to find in previous answers after searching multiple times (hope this is not a duplicate).

I have the following module/class. Let's suppose that I am trying to implement a component which can be dragged around the screen. When the user clicks on it the first time, we start to listen to the mousemove events of the window to know where the user is moving the mouse to. Once the user releases the mouse, we want to remove the event listeners of the window. The code is quite straight forward, and it works if I just code it outside of an iife. However, currently the removeEventListener simply does not work. I guess it might have something to do with the clousure, the scope or something, but I am totally missing it. Thank you very much in advance, here is the code:

MyClass.js

 var myNamespace = myNamespace || {};
 (function(myNamespace){

 var onMouseDragDown = function(e){
          window.addEventListener("mousemove", onMouseDragMove,true);
          window.addEventListener("mouseup", onMouseDragUp,false);
       };

  var onMouseDragUp = function(e){
// This code executes, but the events CONTINUE to be triggered after removing the event listener

//The following lines do not seem to have any effect whatsoever even though they are executed when the user releases the mouse button
      window.removeEventListener("mousemove", onMouseDragMove, true);
      window.removeEventListener("mouseup", onMouseDragUp,false);
  };

  var onMouseDragMove = function(e){
      console.log('moving');
   };

   myNamespace.MyClass = function(param){
      this._param = param;
      this._div = document.createElement('div');  
      this._div = ....

      this._div.addEventListener('mousedown', onMouseDragDown.bind(this), false);
   }

   myNameSpace.MyClass.prototype.getDiv = function (){
      return this._div;
   }
)(myNameSpace);

Index.html

...

        function onCreateNewDocumentClicked(event){
            var myObject = new myNamepace.MyClass(someParams);
            document.body.appendChild(mdi.getDiv());
        }

Upvotes: 2

Views: 2440

Answers (2)

GameAlchemist
GameAlchemist

Reputation: 19294

To remove an event listener, you must provide the exact function that you provided when adding it.
What's happening here is that bind() creates a new function each time, so in fact :

someFunc.bind(someObj) !== someFunc.bind(someObj)

to remove an event listener, you have to store the very function that you provided when adding it.

so store the listener when you add it to be able to remove it later :

var someListener = someFunc.bind(someObj);
element.addEventListener("--", someListener ) ;

// then, later :
element.removeEventListener('--', someListener);

i made a short demo here, when you click on first button it will alert 'hello'.
We see that by removing the listener with a new call to bind, it doesn't remove it.
Then removing the stored function does the job.

http://jsbin.com/EjevIQA/2/edit

Edit : you don't need to add / remove a listener to each div you want dragged. instead, you could just listen to click within the window, and make use of the 'target' information of the event, which will tell which div was clicked.
Maybe you'll want to stop propagation / prevent default when it is a handled div which is clicked, i don't know.

the event handler will look like :

 function handleMouseDown(e) {
     // you might check here which button was clicked (0=left, 2=right)
     var button = e.button;
     // retrieve the target
     var target = e.target ;
     // check if the target is an object we want to drag
     ...
     ... return otherwise.
     // do some things to initialize the drag.
     ...
     // you might want to prevent the click to bubble / trigger default behaviour :
     e.stopPropagation();
     e.preventDefault();
 } 

you set it up once and for all on the window or document object :

document.addEventListener("mousedown", handleMouseDown)

I made a tiny demo here, click on a div to see that it has been identified :
http://jsbin.com/ilavikI/2/edit

Upvotes: 5

jcage
jcage

Reputation: 651

Could it be that your

 .bind(this) 

in

  this._div.addEventListener('mousedown', onMouseDragDown.bind(this), false);

does not return the reference to the same function you are removing?

Upvotes: 1

Related Questions