I have two functions that I use as classes: Person and Eye.
Person creates an Eye object in itself. Later on I try to access the eye object created, with an event handler for whenever the user clicks on the web page.
function Eye(){
this.color="Green";
}
function Person() {
this.name="John";
this.eye = new Eye();
//eye=this.eye; // uncomment and everything works!
document.addEventListener("click", function(){
console.log(name); // This works
console.log(eye); // This doesn't work
})
}
var person= new Person();
Why doesn't this work? Making a second variable eye seems to solve the issue but I have no clue why..
It doesn't work because "eye" is not a variable, it's a property of an object. You're doing nothing to tell JavaScript what object to look at.
You'll have to save the value of this in another local variable:
function Person() {
this.name="John";
this.eye = new Eye();
var person = this;
Then you can use that in the event handler:
console.log(person.eye);
document.addEventListener("click", function() {
console.log(name);
console.log(eye);
});
In this context, name refers to the name property of the window object, since you didn't specify the object off of which you wanted to access it. window.name just so happens to return "result" on my implementation. And ogging eye won't work because eye has not been defined as a variable.
To fix this, use a variable to store the reference to the current object outside the event function and use it inside.
var ref = this;
document.addEventListener("click", function() {
console.log(ref.name);
console.log(ref.eye);
});
Output:
John
Eye { color: "Green" }
Live Demo
Related
Usually I develop on Java, and now I am studying JavaScript/HTML5 Canvas things. And I get a strange situation from Java developer's point of view.
There's a html5 canvas object on the html page, and I want to track the mouse click events on this canvas.
I declared class GameBoard and initialized its properties:
function GameBoard() {
// defining a property for GameBoard class instance
this.myProperty = 'some text here';
// getting canvas element
this.boardCanvas = document.getElementById("myCanvas");
// setting the mouse click event listener
this.boardCanvas.addEventListener("mousedown", this.handleMouseClick, false);
}
and there's a class method to handle mouse click events:
GameBoard.prototype.handleMouseClick = function(event) {
alert(this.myProperty);
}
handleMouseClick() will display undefined because this in handleMouseClick() method refers to the HTML5 Canvas instance (boardCanvas).
My question: how can I refer the current GameBoard class instance inside of handleMouseClick method to get myProperty field value defined in the class constructor?
What I am doing wrong here?
Thank you.
One of the common conventions is to use an alias to this, usually with a variable named self:
function GameBoard() {
// defining alias
var self = this;
this.myProperty = 'some text here';
this.boardCanvas = document.getElementById("myCanvas");
this.handleMouseClick = function()
{
// using alias
alert(self.myProperty);
};
this.boardCanvas.addEventListener("mousedown", this.handleMouseClick, false);
}
However, since you're defining the method on the prototype here, you can either use bind (as proposed by #Alexander) or try this:
var self = this;
this.boardCanvas.addEventListener("mousedown", function(e)
{
// calling the function with 'self/this' context
self.handleMouseClick(e);
}, false);
(Thanks to #Alexander for his contributions)
You can use bind in order to set this for function
this.boardCanvas.addEventListener("mousedown", this.handleMouseClick.bind(this), false);
Example: http://jsbin.com/vutugi/1/
I'm writing an awesome IIFE and want this to be as easy as possible for my users who use it. So I was thinking since some of them don't know that to easily remove an eventlistener without it already being a function we can give that inline function a name
Example
document.addEventListener('click',function dood(){
//some function
},false);
document.removeEventListener('click',dood,false);
//instead of
function dood(){
//some function
}
document.addEventListener('click',dood,false);
document.removeEventListener('click',dood,false);
But since they shouldn't know the name exactly I was wondering if we could do
var k = "name_of_function";
document.addEventListener('click',function window[k](){
//the function
},false);
Though I know this does not work is there a way to do this? I'd like to make it so they can easily do this
object.cancel('name_of_function') //which will be the name of the instance
// they created earlier if they gave that instance a name
object={
cancel:function(nm){
document.removeEventListener(self.trigger,window[nm],false);
//self.trigger really is this.trigger which they assign as either scroll,click,mousemove,etc.
}
};
Any ideas? Or is this not possible at all?
usage is:
scrollex('element',{
max:500,
min:500,
pin:200,
offset:0.5,
name:'google',//this then would be used in multiple instances
});
scrollex.events //shows all events and their names
scrollex.listen('google'); //it'll console log all info for this event
scrollex.cancel('google');
I think you're on the right track. But you should not use window, and some local object instead. And dynamically naming function expressions (or whatever that function window[k](){} was supposed to mean) is impossible a pain - don't try this. Just let them stay anonymous, and reference them only via property names / variables.
var object = (function() {
var listeners = {
name_of_function: function dood(){…}
};
document.addEventListener('click', listeners.name_of_function, false);
return {
cancel: function(nm) {
document.removeEventListener('click', listeners[nm], false);
}
};
}());
// now, you can
object.cancel('name_of_function')
We can modify a DOM element and add to its prototype. For example, if we want to add something only to the canvas, we'd do something like this:
HTMLCanvasElement.prototype.doSomething = function(arg) { ... };
We can then perform this action on a canvas element:
var canvas = document.getElementById('canvasId');
canvas.doSomething(...);
Is it possible to add/attach a function to this instance of the canvas without modifying the prototype of HTMLCanvasElement. I only want a canvas where doSomething(...) was called to have access to the additional methods, not all canvas elements in the DOM. How can I do this?
I've tried the following in my doSomething function:
this.prototype.foobar = function() {...}
However, prototype is undefined here.
Shusl helped me come up with the correct answer. It was easier than I thought. In my doSomething(args) function, instead of trying to modify the object prototype, I just directly attached the function. Here's the full source code:
HTMLCanvasElement.prototype.doSomething = function(args) {
this.foobar = function(args) { ... };
}
var canvas = document.getElementById('canvasId');
canvas.doSomething(...);
canvas.foobar(...);
Now, foobar is only accessible to the instance of the canvas where doSomething was called. At the same time, I don't have to have any information about the instance.
In that case you can directly attache a method to your canvas object
var canvas = document.getElementById('canvasId');
canvas.doSomething= function() {...}; ///doSomething will only be available to this particular canvas.
canvas.doSomething(...);
With jQuery, you can use the data property.
//setting the function
$('element').data('doSomething', function(arg) { ... });
//calling the function
$('element').data('doSomething')(arg);
JSFiddle
Object.defineProperty(element, 'doSomething', {value:function(arg){ ... }} );
Where 'element' is the element you want to add the property to,
'doSomething' is the name and the
third argument is an object of the property its self. In your case a function.
For example:
var mycanvas = document.createElement("canvas");
Object.defineProperty(mycanvas, 'doSomething', {
value: function(x){console.log(x); },
configurable: true
});
mycanvas.doSomething('my message');
//prints 'my message' to the console.
The 'configurable' property specifies if you would like the 'doSomething' property to be able to be changed again after it is created. Check out the MDN Details for more information and examples.
I'm now trying to register a mouse event listener on a canvas element.
As my JS application object initializes, it binds mouse events to a custom "MouseController" class:
this.canvas.addEventListener('mousedown',this.input0.btnDown, false);
"this" is the application object being initialized and canvas is a reference to the basic HTML5 canvas on my page.
The controller is a simple class like:
function MouseController(eventHandler) {
this.handler = eventHandler;
this.contact = false;
this.coordX = 0;
this.coordY = 0;
}
MouseController.prototype.btnDown = function(event) {
// Faulty line ???
this.updateCoordinates(event);
}
MouseController.prototype.updateHIDCoordinates = function (event) {
// code to set coordX and coordY of the controller instance
// Again, I can't access the object from here as "this" refers to the Canvas
}
As the mouse is clicked, the console logs "result of expression this.updateCoordinates' is not a function". A previous discussion taught me about the reference "this" being lost, ending up being bound to, in this case, the Canvas item.
So I'm looking for a way to call "btnDown" like I would in java, meaning that it executes as part of an object and thus has access to the variables of that object.
The only solution I found was a singleton... No good :( I'm sure there's a clean solution...
Please help :-)
Thanks!
J.
Either create a closure:
var controller = this.input0;
this.canvas.addEventListener('mousedown', function(event){
controller.btnDown(event);
}, false);
or use ECMAScript 5's .bind() [MDN]:
this.canvas.addEventListener('mousedown', this.input0.btnDown.bind(this.input0), false);
Also note that your other method is called updateHIDCoordinates, not updateCoordinates.
I have an object I created in JavaScript. Let's say it looks like this:
function MyObject() {
this.secretIdea = "My Secret Idea!";
};
MyObject.prototype.load = function() {
this.MyButton = $(document.createElement("a"));
this.MyButton.addClass("CoolButtonClass");
this.MyButton.click = MyButton.onButtonClick;
someRandomHtmlObject.append(this.MyButton);
};
MyObject.prototype.onButtonClick = function(e) {
alert(this.secretIdea);
};
As you can see, I have an object setup in JavaScript and, when it's loaded, it creates an anchor tag. This anchor tag as a background image in CSS (so it's not empty).
Now, I understand that the 'this' statement, when the button would actually be clicked, would fall to the scope of the MyButton element rather than the object I have created.
I have tried using call(), try() and bind() and I cannot get this to work. I need it so that, when the button is clicked, it goes back to the object's scope and not the html element's scope.
What am I missing here?
The this value inside the click event handler refers to the DOM element, not to the object instance of your constructor.
You need to persist that value, also you refer to MyButton.onButtonClick I think you want to refer the onButtonClick method declared on MyObject.prototype:
MyObject.prototype.load = function() {
var instance = this;
//..
this.MyButton.click(function (e) { // <-- looks like you are using jQuery
// here `this` refers to `MyButton`
instance.onButtonClick(e);
});
//...
};