Javascript call function with “this” on event [duplicate] - javascript

I have created a 'control' using jQuery and used jQuery.extend to assist in making it as OO as possible.
During the initialisation of my control I wire up various click events like so
jQuery('#available input',
this.controlDiv).bind('click', this, this.availableCategoryClick);
Notice that I am pasing 'this' as the data argument in the bind method. I do this so that I can get at data attached to the control instance rather from the element that fires the click event.
This works perfectly, however i suspect there is a better way
Having used Prototype in the past, I remember a bind syntax that allowed you to control what the value of 'this' was in the event.
What is the jQuery way?

You can use jQuery.proxy() with anonymous function, just a little awkward that 'context' is the second parameter.
$("#button").click($.proxy(function () {
//use original 'this'
},this));

I like your way, in fact use a similar construction:
$('#available_input').bind('click', {self:this}, this.onClick);
and the first line of this.onClick:
var self = event.data.self;
I like this way because then you get both the element clicked (as this) and the "this" object as self without having to use closures.

jQuery has the jQuery.proxy method (available since 1.4).
Example:
var Foo = {
name: "foo",
test: function() {
alert(this.name)
}
}
$("#test").click($.proxy(Foo.test, Foo))
// "foo" alerted

I don't think jQuery has a built-in feature for that. But you could use a helper construct like the following:
Function.prototype.createDelegate = function(scope) {
var fn = this;
return function() {
// Forward to the original function using 'scope' as 'this'.
return fn.apply(scope, arguments);
}
}
// Then:
$(...).bind(..., obj.method.createDelegate(obj));
This way, you can create dynamic 'wrapper functions' with createDelegate() that call the method with a given object as its 'this' scope.
Example:
function foo() {
alert(this);
}
var myfoo = foo.createDelegate("foobar");
myfoo(); // calls foo() with this = "foobar"

HTML 5-compliant browsers provide a bind method on Function.prototype which is, probably the cleanest syntax and is not framework-dependent, though it is not built into IE until IE 9. (There is a polyfill for browsers without it, though.)
Based on your example, you can use it like this:
jQuery('#available input',
this.controlDiv).bind('click', this.availableCategoryClick.bind(this));
(side note: the first bind in this statement is part of jQuery and has nothing to do with Function.prototype.bind)
Or to use slightly more concise and up-to-date jQuery (and eliminate confusion from two different kinds of binds):
$('#available input', this.controlDiv).click(this.availableCategoryClick.bind(this));

you can use the javascript bind method like this:
var coolFunction = function(){
// here whatever involving this
alert(this.coolValue);
}
var object = {coolValue: "bla"};
$("#bla").bind('click', coolFunction.bind(object));

jQuery does not support binds and the preferred way is to use functions.
Because in Javascript, this.availableCategoryClick does not mean calling the availableCategoryClick function on this object, jQuery advise to use this preferred syntax:
var self = this;
jQuery('#available input', self.controlDiv).bind('click', function(event)
{
self.availableCategoryClick(event);
});
OO concepts in Javascript are hard to understand, functionnal programming is often easier and more readable.

Seeing that functions changes scope, the most common way is to do it by hand, with something like var self = this.
var self = this
$('.some_selector').each(function(){
// refer to 'self' here
}

Related

What's the best or most common way to pass an object's method as a callback?

I've run into the problem where I need to pass an object's method as a callback, and that method uses this. Obviously this can't work because when invoked as a callback (not through the owning object) this will point to the global object.
I read about solutions to this problem and am wondering what the best or most common one is.
Currently, my 'class' looks like this:
function MyClass(value) {
this.value = value;
}
MyClass.prototype.alertValue = function() {
alert(this.value);
};
Options A - Change the class to look like this:
function MyClass(value) {
this.value = value;
this.alertValue = function() {
alert(value);
};
}
The advantage - simple. But the disadvantage is that alertValue will be copied on every instantiation, which is the reason why we usually put methods on the prototype.
Option B - Use .bind():
callbackReceivingFunction(myObject.alertValue.bind(myObject));
I can write a utility method for this:
function bind(object, methodName) {
return object[methodName].bind(object);
}
What's the most common approach to solve this problem? What are its pros and cons? Both ways I came up with seem inelegant, is there another way?
I would suggest using bind(). Keep in mind IE <= 8 does not support Function.prototype.bind() so you'd want to use a polyfill. If you have to bind a bunch of methods for a single class, check out Underscore/lodash's _.bindAll() method.
For example:
_.bindAll(myObj, 'alertValue', 'otherMethod', 'anotherMethod')

Object oriented design in javascript and 'this' pointer

I am creating a object in javascript like this
function myobject() {
this.myvar1 = 0;
this.myvar2 = 0;
}
myobject.prototype.a = function(){
this.myvar1 +=1;
$('#button').click(function () { // 'this' is undefined
alert(this.myvar1)
})
}
var mything = new myobject();
mything.a()
What is the proper way to pass the this pointer to an anonymous function?
For updated question:
The issue is that inside that event handler, this refers to the element you clicked on, rather than your myobject, so just keep a reference to it, like this:
myobject.prototype.a = function(){
this.myvar1 +=1;
var self = this;
$('#button').click(function () {
alert(self.myvar1)
});
}
You can test it out here.
For previous question:
What you have should work (exactly as you have it), you can test it here.
Adding the following code to the end of your snippet and running it correctly alerts '1':
mything.b();
alert(mything.myvar1);
What were you expecting? Perhaps you're incorrectly invoking mything.b() ?
To pass this to an inner function, "save" it to another variable.
myobject.prototype.a = function() {
var self = this;
self.myvar1 += 1;
$('#button').click(function () {
alert(self.myvar1);
});
}
What's happening here is that jQuery is hijacking the value of this in the anonymous function used as a handler for the click event. It's kind of confusing, but jQuery's behavior is to assign the DOM element that triggered the event to this. There are a couple ways to set the value of this explicitly (the "context") for the callback function:
Function.prototype.bind - Part of the ECMAScript 5 standard, just starting to be implemented in browsers. For legacy support, you can extract it from the Prototype library.
$.proxy - jQuery's crappy equivalent of Function.prototype.bind, which was introduced in jQuery 1.4.
I wrote a couple posts on my blog that explain these in more detail if you're interested:
Organizing JavaScript with Namespaces and Function Prototypes
Understanding jQuery 1.4's $.proxy() method
In both cases, since this will now be your object and not the triggering DOM element, you can get the triggering DOM element by inspecting the event object, which will be the second parameter to your callback function.
Others here have done a nice job explaining the issue and how to resolve without adding any dependencies, but personally I think this plugin is a better overall solution (if you don't mind the dependency):
http://markdalgleish.com/projects/eventralize/

What's difference between "$.FunctionName()" and "FunctionName()"?

what's the difference between a jQuery function
$.FunctionName = function(){ alert('Hello!') }
and normal javascript function?
function FunctionName(){ alert('Hello!') }
The former becomes a static method of the jQuery object.
The latter becomes just a regular function.
The only difference, really is the owner of the function. The jQuery object/constructor owns the first method, while the window object owns the second method, assuming it wasn't defined in another function scope.
Generally, you do not usually do the first one unless you want to attach a specific method that's related to jQuery. If you have a custom application specific function do the latter.
There is no significant differences. Both functions will work the same.
If you want to create you own functions library, better way is create new class (named not $) like
my_lib={} and then add functions to it like
my_lib.FunctionName = function(){ alert('Hello!'); }
Or
my_lib={
FunctionName: function(){ alert('Hello!'); }
}

Calling class methods within jQuery function

So I have some javascript class and in one method I use jQuery to bind function to click event. And within this function I need to call other methods of this class. In usual js function I did it through "this.method_name()", but here, I guess, jQuery redefines "this" pointer.
jQuery doesn't redefine the this pointer, but that's how JavaScript functions work in general. Store a reference to the this pointer under a different name, and use that.
var self = this;
$("selector").click(function() {
self.method_name();
});
See this answer for more approaches.
There are a few different ways to do this.
Anurag has a perfect example of one.
Two other ways are the jQuery Proxy class (Mentioned in other answers) and the 'apply' function
Now lets create an object with click events:
var MyObj = function(){
this.property1 = "StringProp";
// jQuery Proxy Function
$(".selector").click($.proxy(function(){
//Will alert "StringProp"
alert(this.property1);
// set the 'this' object in the function to the MyObj instance
},this));
//Apply Function
//args are optional
this.clickFunction = function(arg1){
alert(this.property1);
};
$(".selector").click(this.clickFunction.apply(this,"this is optional"));
};
In addition to the possibility of temporarily storing a reference to this (self = this, see Anurag's answer), since ES6 it is possible to use arrow functions for this problem. These have no "own" this.
This means that the "usual" object-related this can be accessed again within an arrow function within an event handler:
$("selector").click(() => {
this.method_name();
});
Further information:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions?retiredLocale=de#cannot_be_used_as_methods
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions?retiredLocale=de#using_call_bind_and_apply

Javascript question: Problem with calling an objects methods

Say I have an object called FieldEdit. I define the function constructor for this object, instantiate it via. var obj = new FieldEdit(), and define its methods by FieldEdit.prototype.<method name> = function() { ... }.
Under what situations would calling this object's methods within the objects' other methods (via. this.<method name>();) fail?
Note that I want to avoid posting a code sample for this if I can since I think this is simply a problem with my understanding of Javascript more than anything, really. I'm pretty sure my code is sound, to the best of my knowledge (and it's my knowledge that's the question here, besides).
The most likely scenario where this would reference an object other than FieldEdit during execution of FieldEdit methods is within a nested scope like a closure, an event handler, or any function or method called explicitly with .call(someOtherScope) or .apply(someOtherScope, args).
You can work around that, of course, by maintaining a variable reference to the FieldEdit instance and using FieldEditInstance.<method>() instead.
PrototypeJS allows you to wrap functions with Function.bind for this purpose, but it's easily accomplished otherwise, either with:
var FieldEditInstance = this;
obj.methodThatUsesACallback(function() {
// use that instead of this
});
OR
var FieldEditInstance = this;
var callback = function() {
// ...
};
// This is more or less what PrototypeJS' Function.bind produces
var boundCallback = function() {
return callback.apply(FieldEditInstance, arguments);
};
obj.methodThatUsesACallback(boundCallback);

Categories

Resources