I already saw this thread, but I think my case is a bit different.
This is an example class, whose constructor receives an element as parameter, that can be moved dragging it. But it does not stop being dragged on mouse up. If I good understood what I read in the other thread, I guess I have to assign the methods to variables, but I don't know how, as they take the event
parameter:
class Example
{
rect;
constructor(rect)
{
this.rect = rect;
this.rect.addEventListener('mousedown', event => this.onMouseDown(event));
}
onMouseDown(event)
{
document.addEventListener('mousemove', event => this.onMouseMove(event));
document.addEventListener('mouseup', event => this.onMouseUp(event));
}
onMouseMove(event)
{
this.rect.style.left = event.clientX;
this.rect.style.top = event.clientY;
}
onMouseUp(event)
{
document.removeEventListener('mousemove', this.onMouseMove);
document.removeEventListener('mouseup', this.onMouseUp);
}
}
document.addEventListener("DOMContentLoaded", function()
{
var rect = document.getElementById('rect');
var ex = new Example(rect);
});
#rect {
position: absolute;
border: 1px solid #ccc;
background-color: #DFD;
width: 100px;
height: 100px;
}
<html>
<head>
<meta charset="utf-8"/>
<title>Test</title>
</head>
<body>
<div id="rect"></div>
</body>
</html>
I don't know why the snippet here does not work, I copied the code from some files, that perfectly work.
TL;DR the easiest thing to do here is this.rect.addEventListener('mousedown', this.onMouseDown);
and change your class methods to fat arrow functions onMouseDown = (event) => {...}
When you add an event listener, you need to keep a reference to the function you added to remove it. When you do this:
document.addEventListener('mousemove', event => this.onMouseMove(event));
You're creating an entirely new function using the =>
"fat arrow" operator. Your code is equivalent to this:
onMouseDown(event) {
const listener = event => this.onMouseMove(event);
document.addEventListener('mousemove', listener);
}
You can see that the listener
function only exists inside the onMouseDown
method. There's no way to access it in other methods.
So when you run this line, later:
document.removeEventListener('mousemove', this.onMouseMove);
Nothing happens, because the reference to your method this.onMouseMove
is not the same as listener
. They are different functions.
You should research this
, and methods
vs functions
in Javascript. This type of issue comes up a lot when dealing with classes and events.
There a few ways to solve this problem. First of all, change your code to bind the class method, so that we can remove it later:
this.rect.addEventListener('mousedown', this.onMouseDown);
But there's a problem here. When you pass in this.onMouseDown
to addEventListener
, you're binding the event listener to the function onMouseDown
. When you do this, it becomes a "function," not a "method". It loses its relationship to the Example
class, so that when onMouseDown
runs, this
will no longer be the instance of Example
. So when the code executes with:
document.addEventListener('mousemove', event => this.onMouseMove(event));
this
will no longer point to the class instance, and the code will error rather than add an event listener.
A handy trick in Javascript to get around this issue is to instead define methods with the fat arrow operator, which makes them always use the parent's this
, which will be your class instance. Here's the full code:
class Example {
rect;
constructor(rect) {
this.rect = rect;
this.rect.addEventListener('mousedown', this.onMouseDown);
}
onMouseDown = () => {
document.addEventListener('mousemove', this.onMouseMove);
document.addEventListener('mouseup', this.onMouseUp);
}
onMouseMove = (event) => {
this.rect.style.left = event.clientX;
this.rect.style.top = event.clientY;
}
onMouseUp = (event) => {
document.removeEventListener('mousemove', this.onMouseMove);
document.removeEventListener('mouseup', this.onMouseUp);
}
}