Call back function using `this` in Jquery get() - javascript

I want to use this keyword in the callbacks of $.get(). My code structure is
var myObject = {
get: function() {
$.get(server,data,function(data,status) {
this.callback();
});
},
callback: function() {
}
}
I don't want to use myObject.callback(). Is there any way to accomplish using this.callback()?

You can .bind() the value of this to your callback function before passing it to $.get():
var myObject = {
get: function() {
$.get(server, data, function(data, status) {
this.callback();
}.bind(this));
}
callback: function {
// do something here
}
}
Of course, that assumes the value of this within your own myObject.get() function is correct, which it would be if you called it with "dot notation" as myObject.get().
Note also that if the only thing your anonymous function does is call the other function then you can bind the other function directly:
var myObject = {
get: function() {
$.get(server, data, this.callback.bind(this));
}
callback: function {
// do something here
}
}

Option #1 -- cache this in a variable (_this):
var myObject = {
get: function() {
var _this = this;
$.get(server, data, function(data, status) {
_this.callback(); // this keyword refers to Window obj not myObject
});
}
callback: function {
// do something here
}
}
Option #2 -- use jQuery's .proxy method:
var myObject = {
get: function() {
$.get(server, data, $.proxy(function(data, status) {
_this.callback(); // this keyword refers to Window obj not myObject
}), this);
}
callback: function {
// do something here
}
}
(Edited-- thanks nnnnnn)

Related

Using this inside an Javascript IIFE within an object

I would like to use this instead of the name of the object inside the IIFE.
var ops = {
start: (function (){
socket.on('set', function(data) {
ops.getData();
});
}()),
getData: function (){
...
}
};
How it can be done?
You cannot. Not to mention that your function does not return anything to assign to ops.start.
var ops = {
start: function (){
var self = this;
socket.on('set', function(data) {
self.getData();
});
}
};
ops.start();
You could use getter and closure on your function context if needed. Getter automatically invokes a function:
var ops = {
get start() {
return socket.on('set', function(data) {
ops.getData();
});
},
getData: function (){
}
};
Now you can just refer to ops.start
You can create a new object and use it's prototype to access "this":
var o = Object.create(Object.prototype, {
data: {
value: 12
},
getobject: {
get: function() {
return this.data;
}
}
});
o.getobject;

Store instance for usage in nested map/object

I have a really annoying scope issue for my JQuery Widget. Essentially I need to access the widget instance (this) inside of my map/object options.
Is it possible to do this? Any advice how I can achieve this?
$.widget( "my.myWidget", {
// Below 'this.defCallback' will be undefined
// How can I store 'this' (the widget instance) in a variable??
options: {
callback: this.defCallback // allow user to overwrite/provide custom callback
},
....
defCallback: function() {
console.log('defCallback');
}
});
If I had a nested function I know I can easily solve this but I have a nested object/map which makes things difficult.
function foo {
var _this = this;
...
var bar = function() {
// easily access this
_this.defCallback();
...
}
}
Usage:
$('<div></div>')
.myWidget(); // use defCallback
$('<div></div>')
.myWidget({
callback: function() {
...
}
}); // use custom callback
Edit: How the callback function is 'bound' and called:
_create: function() {
this.element.click( this.options.callback );
}
.click(value.callback(_this)
In javascript you could dynamically change the context of a function with the apply() and with call() methods.
On es5 you could use bind().
So your code:
_create: function() {
this.element.click( this.options.callback );
}
Became with apply():
_create: function() {
var el = this.element;
var callback = this.options.callback;
el.click(function() {
callback.apply(el);
// If you have parameters:
// callback.apply(el, arguments || array);
});
}
With call():
_create: function() {
var el = this.element;
var callback = this.options.callback;
el.click(function() {
callback.call(el);
// If you have parameters:
// callback.call(el, arg0, arg1, ...);
});
}
With bind():
_create: function() {
this.element.click(this.options.callback.bind(this));
}
UPDATE
As your issue is to have the this reference binded inside the object definition you need to change your code.
The quick way is is to emend it like this (from your fiddle):
var mw = {
defCallback: function () {
alert("abc");
},
_create: function () {
//this.populateOptions();
alert("Is undefined: " + this.options.isUndefined); // outputs 'true'
this.element.click(this.options.callback.bind(this));
},
populateOptions: function() {
if (this.options.callback === undefined)
this.options.callback = this.defCallback;
}
};
So you first define your object with the parent attributes and functions.
mw.options = {
//accessObjectParent: this.instantiator,
isUndefined: (mw.defCallback === undefined), // this refers to the map/object
// Can I access the maps 'parent'/instantiator?
// this.instantiator.defCallback ???
callback: mw.defCallback
};
Than you attach the options object and you could refer on the parent object instead of using this.
$.widget( "my.myWidget", mw );
And now you pass the object on your widget declaration.

Object as jQuery.fn prototype?

If I define prototype like this
jQuery.fn.myFunc = function() {
console.log(this);
}
and call it like this:
$('div').myFunc();
this inside of myFunc will refer to jQuery object selection.
Now if I don't want to pollute .fn with multiple attached functions, can I do something like
jQuery.fn.myPlugin = {
myFunc1: function() {
},
myFunc2: function() {
}
}
If I call it $('div').myPlugin.myFunc1(); - how do I get reference to selected objects inside of myFunc1? Or is there a different, better approach?
Nope. can't do it that way. Instead, define it as a function, then add properties to that function.
jQuery.fn.myPlugin = function() {
console.log(this);
};
jQuery.fn.myPlugin.myFunc1 = function() {
};
jQuery.fn.myPlugin.myFunc2 = function() {
};
note that myFunc1 and myFunc2 still wont' have access to the selected element, therefore it's relatively useless to define them this way other than the fact that they can be easily overridden by other developers (which is a good thing)
The normal way of having additional methods within your plugin is to have your plugin method accept a parameter that can eitehr be an object to init the plugin, or a string to execute a target method on the element. for example, $("somediv").myPlugin("myFunc1")
The jQuery plugin tutorial suggests this:
(function( $ ) {
$.fn.popup = function( action ) {
if ( action === "open") {
// Open popup code.
}
if ( action === "close" ) {
// Close popup code.
}
};
}( jQuery ));
I suppose this would be another alternative:
(function($) {
$.fn.myPlugin = function (action) {
var functions = {
open: function () {
console.log('open: ', this);
},
close: function () {
console.log('close:', this);
}
}
if (action && functions[action]) {
functions[action].call(this)
} else {
console.log('no function', this);
}
return this;
};
}(jQuery));
$('#theDiv')
.myPlugin()
.myPlugin('open')
.myPlugin('close');
http://jsfiddle.net/faJAk/
work if you create a object before.
Like this:
<script>
jQuery.fn.myPlugin = {};
jQuery.fn.myPlugin = {
myFunc1: function() {
console.log(this);
},
myFunc2: function() {
alert(this);
}
};
$(document).ready(function(){
$('div').myPlugin.myFunc1();
$('div').myPlugin.myFunc2();
});
</script>
Another possible approach is to use defineProperty:
(function($) {
var myPlugin = {
foo: function() {
console.log(this)
}
}
Object.defineProperty($.fn, "myPlugin", {
get : function() { return $.extend({}, this, myPlugin) }
});
})(jQuery);
Now $(...).myPlugin.foo should resolve this correctly:
$(function() {
$("body").myPlugin.foo(); // logs "body"
})

Accessing a containing object from with in its method?

In the snippet below, an object literal holds properties, one of which is a method that needs access to the the object literal.
However, b.c. it is only used as an event handler callback, this always points to the element that triggered the event.
I need to access the containing object.
Otherwise, I'm forced to put a function in a function which seems odd.
/***************************************************************************************************
**MSimMenu - simple drop down menu
*/
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
// in mouseout this points to the element that triggered the event
// need access to containing object
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
init: function () {
var self = this;
// tempoaray fix - function in function seems odd
function mouse_out() {
self.A.time_out_id = NS.setTimeout(self.hideBottom, self.A.TIME_DELAY);
}
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
self.E.hold_name.addEventListener("mouseout", mouse_out, false);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
Final Code Using Bind
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
init: function () {
var self = this;
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", self.mouse_out.bind(self), false);
self.E.hold_name.addEventListener("mouseout", self.mouse_out.bind(self), false);
},
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
I have seen alot of people create a variable to assign the object to and then use the variable.
var that = {
myfunc:function(){
console.log(that)
}
};
NS.parsel(that);
I actually like moving most of the logic into the init method. Provides nice encapsulation with an easy way to declare public and private methods/variables. For example:
NS.parsel({
init: function() {
var self = this;
//public instance variable
self.Name = 'MSimMenu';
//private instance variables
var A = {
time_out_id: null,
TIME_DELAY: 1000
};
var E = {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
};
//public instance method
self.showBottom = function () {
E.wrap_bottom.style.visibility = 'visible';
};
//private instance method
E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
function mouse_out() {
A.time_out_id = NS.setTimeout(self.hideBottom, A.TIME_DELAY);
}
}
});
There's a lot of ways you can get what you want.
One trick you can do is to not use the mouse_out function directly, but provide a helper function like get_mouse_out() that returns a bound version of the function.
var myobject = {
data:"Some data",
_mouse_out: function() { console.log(this.data); }
get_mouse_out: function() {
var self = this;
return function(){ return Function.apply(self._mouse_out,self,arguments); }
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//This doesn't work.
do_callback( myobject._mouse_out);
//But this does
do_callback( myobject.get_mouse_out() );
EDIT: Improved version inlining _mouse_out and using bind.
var myobject = {
data:"Some data",
get_mouse_out: function() {
function _mouse_out() { console.log(this.data); }
return _mouse_out.bind(this);
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//But this does
do_callback( myobject.get_mouse_out() );
If you're willing to have init be called as setup before mouse_out is used then you can do this.
var myobject = {
data:"Some data",
init: function() {
function _mouse_out() { console.log(this.data); }
this.mouse_out = _mouse_out.bind(this);
}
}
myobject.init();
fn( myobject.mouse_out );
Finally there's a nice variant on Shanimals that works a similar way, but provides encapsulation.
NS.parcel( (function(){
var myobj = {};
myobj.data = "Some data";
myobj.mouse_out = function(){ console.log(myobj.data); }
return myobj;
})()
);

init function and the object in Javascript

I have the following (simplified) code:
var Foo = (function () {
var data = {},
settings = {
// default settings here
};
function bar(callback) { // bar is an asynchronous function
var result = null;
// fiddle around until you get a result
if (callback) {
callback(result);
}
}
return {
init: function (options, callback) {
var kallback = callback;
$.extend(settings, options);
bar(function () {
if (kallback) {
kallback(WHAT_GOES_HERE);
}
});
},
debug: function () {
return {
settings: settings,
data: data
};
},
set: function (k, v) {
settings[k] = v;
},
get: function (k) {
return settings[k];
}
};
}());
The code above is in a js file, then in the footer of the page in question:
<script type="text/javascript">
Foo.init({ option1: "value", option2: "value" }, function (obj) {
console.log("The object was ", obj);
});
</script>
Basically, here is what I want to be able to do:
Create an object (with a set of optional params, but not important for this question)
During the creation phase of the object, have it call an asynchronous function
When the asynchronous function is done, I should be able to trigger a callback, and the argument for the callback should be the intialized object
I thought that this would work for WHAT_GOES_HERE above, but turns out, at least when I've tested it, that this is the DOM Window object.
First of all, am I constructing this object correctly? Or is there a better way to create it?
Secondly, assuming I am doing this right, what should go in the WHAT_GOES_HERE so that when console.log("The object was ", foo); runs, the value for obj is the created Foo object?
Yes, in an anonymous function called this way, this will refer to the window object. To refer to the this reference from the init method you have to store the reference in another variable:
var kallback = callback, self = this;
$.extend(settings, options);
bar(function () {
if (kallback) {
kallback(self);
}
});
Your way of constructing the object works, as long as you only want to have one single foo object.

Categories

Resources