Reputation: 2254
Below is my code when I add eventlistener in my object:
this.canvas.addEventListener('mousemove', function (e) {
var canv = document.getElementById("some");
myGameArea.x = (e.clientX - canv.getBoundingClientRect().left);//Look at canv
myGameArea.y = (e.clientY - canv.getBoundingClientRect().top);//Look at canv
});
It works, but only when i use getElementById to find my canvas element and then use canv for my needs. But if i do this:
this.canvas.addEventListener('mousemove', function (e) {
var canv = document.getElementById("some");
myGameArea.x = (e.clientX - this.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - this.canvas.getBoundingClientRect().top);//Look at this.canvas
});
Then myGameArea doesnt change at all and my debugger tells this: "Uncaught TypeError: Cannot read property 'getBoundingClientRect' of undefined at HTMLCanvasElement.". I have declared canvas in my object before this part of code and i used this.canvas for a lot of other functions. So where is my problem?
Upvotes: 0
Views: 114
Reputation: 8921
Unlike normal variables, the value of the this
keyword doesn't depend on where the function you're accessing it from is defined, but how it is called. In your case, this
is being overwritten in the handler. A quick workaround would be the following:
var that = this;
this.canvas.addEventListener('mousemove', function (e) {
myGameArea.x = (e.clientX - that.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - that.canvas.getBoundingClientRect().top);//Look at this.canvas
});
Here we explicitly state the object we want to access, and thus don't need to use this
at all. However, this is not considered best practice. The recommended way to deal with nested scope is to bind
the function to the context you want:
this.canvas.addEventListener('mousemove', function (e) {
myGameArea.x = (e.clientX - this.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - this.canvas.getBoundingClientRect().top);//Look at this.canvas
}.bind(this));
Or, if you're using ES6, use fat arrow notation (() => {}
), which doesn't create its own context, for the handler:
this.canvas.addEventListener('mousemove', (e) => {
myGameArea.x = (e.clientX - this.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - this.canvas.getBoundingClientRect().top);//Look at this.canvas
});
Upvotes: 0
Reputation: 1396
Within the callback closure, the context of this
is the canvas element itself. Therefore, you would just use this
to reference the canvas.
this.canvas.addEventListener('mousemove', function (e) {
myGameArea.x = (e.clientX - this.getBoundingClientRect().left);
myGameArea.y = (e.clientY - this.getBoundingClientRect().top);
});
Upvotes: 2
Reputation: 6706
In the callback function of addEventListener
, this
is no longer the same value that it was outside of the callback. If you would like to bind to the same this
value you can use either .bind(this)
or use arrow func:
this.canvas.addEventListener('mousemove', function (e) {
var canv = document.getElementById("some");
myGameArea.x = (e.clientX - this.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - this.canvas.getBoundingClientRect().top);//Look at this.canvas
}.bind(this));
this.canvas.addEventListener('mousemove', (e) => {
var canv = document.getElementById("some");
myGameArea.x = (e.clientX - this.canvas.getBoundingClientRect().left);//Look at this.canvas
myGameArea.y = (e.clientY - this.canvas.getBoundingClientRect().top);//Look at this.canvas
});
Upvotes: 0