views:

214

answers:

3

Hi there. I have a constructor with these methods:

    
function getMouseXY(event){
        var x = event.clientX - this.offsetLeft;
        var y = event.clientY - this.offsetTop;
    return [x,y];
}

function alertx(){
    var c = this.getMouseXY(event);
    alert(c[0]);
}

In the HTML code i assign the alertx function to a HTML5 canvas' event mouseup:

document.getElementById('cbackground').addEventListener('mouseup', object.alertx, false);

What's the expected result? That clicking on the canvas it shows the X position of the mouse, instead i get nothing. Further exploration with Firebug gets me the error "event is not defined". I don't know how to avoid that! Any tips? Thanks!

A: 

On var c = this.getMouseXY(event); you are passing an unassigned variable (event) to the function, which is why it is blowing up. Maybe you forgot to add in the argument to alertx()?

envalid
I just used event to make the clientY and clientX functions to work, not because i wanted so... :( Don't know how to handle it inside alertx.
Gabriel A. Zorrilla
A: 

In function alertx event is never initialized.

If you use function alertx(event) it should work.

stimpie
Doing so renders another error, this.getMouseXY is not a function...
Gabriel A. Zorrilla
+3  A: 

Let's see a couple of issues:

  1. The alertx() doesn't receive an event argument.
  2. In that function you are calling getMouseXY using this. The this keywords at that moment, will refer to the element that triggered the event.
  3. You are binding the event handler to an unknown object variable.

I think you want to do something like this:

function getMouseXY(event){
        var x = event.clientX - this.offsetLeft, // notice, 'this' is used
            y = event.clientY - this.offsetTop;

    return [x,y];
}

function alertx(event){
    var c = getMouseXY.call(this, event); // set the element as 'this'
    alert(c[0]);
}

And if you have a constructor function, and the above functions are instance methods, you can do something like this:

function MyObject () {  // constructor
}

MyObject.prototype.getMouseXY = function (event) {
        var x = event.clientX - this.offsetLeft,
            y = event.clientY - this.offsetTop;

    return [x,y];
};

MyObject.prototype.alertx = function (event, element) {
    var c = this.getMouseXY.call(element, event); 
    alert(c[0]);
}

When binding the event, you can add an anonymous function, to enforce the context:

var object = new MyObject();
document.getElementById('cbackground').addEventListener('mouseup', function (e) {
  object.alertx(e, this); // alertx will be called with the correct 'this'
}, false);


Edit: In response to your comment, you just have to know how the context (the this keyword) is set implicitly:

When you call a instance method like:

obj.method();

The this keyword inside the method, will refer to obj.

The same thing happens when you call global variables, since they are members of the global object (window in browser scripting):

globalFunction();

Is equivalent to:

window.globalFunction();

And the context inside that function will be the global object itself (window).

Another case happens when you use the new operator:

var instance = new MyConstructor();

The this keyword in that case will be a new object, created by the use of the new operator.

When you use a function as an event handler, the this keyword will refer to the element tha triggered the event:

document.getElementById('myId').onclick = obj.myFunction;

In that case myFunction is a instance method of obj, but the this keyword will refer to the DOM element that has been clicked.

And finally, as you saw in my code, the context can be set explicitly by the use of call or apply.

CMS
Amazing man, thanks! The .call solved the problem. I'll read more about it. I DO have a constructor, and those functions are methods of it, what's the advantage of prototyping in this case?
Gabriel A. Zorrilla
Humm. I modified the code to make it compliant to the prototyping model (constructor, add method by prototyping them, your second case) and i'm getting a "this.getmouseXY is undefined".
Gabriel A. Zorrilla
@Gabriel: Could you post the code, in your question or in http://jsbin.com ?
CMS
You are free to check map.js here : http://pastebin.com/m1fd1c164
Gabriel A. Zorrilla
Did you see anything odd CMS?
Gabriel A. Zorrilla