jQuery callback and prototype inheritance - javascript

I create the following class :
APP.core.View = function () {
var self = this;
$.ajax ( { url: 'test.html' } ).done ( self.build );
return self;
};
APP.core.View.prototype.build = function ( source ) {
var self = this;
// this refers to the AJAX callback.
return self;
};
As you can see in the build method, the reference to this (the one belonging to APP.core.View) has been lost. How can I get it back ? I know I could pass a ref to this in the AJAX callback like this :
$.ajax ( { url: 'test.html' } ).done ( function ( source ) {
self.build ( source, self );
} );
But I don't really like it as I feel like a method should never loose the ref to its object.
Any idea/suggestion ? :)

You can use $.proxy() to create a cross platform solution
APP.core.View = function () {
$.ajax({
url: 'test.html'
}).done($.proxy(this.build, this));
return this;
};
For modern browsers, you can use .bind()
APP.core.View = function () {
$.ajax({
url: 'test.html'
}).done(this.build.bind(this));
return this;
};

I just found another answer in the jQuery AJAX doc. The jQuery.ajax function provides a context argument which lets you specifies the callbacks context. Example :
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
$( this ).addClass( "done" );
});
Source : http://api.jquery.com/jQuery.ajax/

Related

Method undefined when calling it from $ajax.success

When I call a method from the $ajax.success callback I get an undefined.
var someObj = {};
someObj.someMethod = function() {
//code code
}
someObj.ajaxCall = function() {
$.ajax({
//ajax options
})
.done(function( data ) {
this.someMethod();
});
}
As our good friend, Mr. SLaks has pointed out, you have a scope issue with regards to this
One solution other than the one posted could be saving a reference to the scope before the callback :
someObj.ajaxCall = function() {
var _this = this;
$.ajax({
//ajax options
})
.done(function( data ) {
_this.someMethod();
});
}
Or, you can use the context option with $.ajax() to control the setting of the this value:
someObj.ajaxCall = function() {
$.ajax({
context: this,
// other ajax options
})
.done(function( data ) {
this.someMethod();
});
}
You should use the call method of the function object:
someObj.ajaxCall = function() {
$.ajax({
//ajax options
})
.done(function( data ) {
someMethod.call(someObj);
});
}
Inside the success callback the this object is pointing the $ajax object which haven't a someMethod function defined.

JS object method call not working from callback

I have a small problem with prototyped JS coding, and with callbacks. It looks like not working properly.
Here is my sample:
var hl = new HeaderLogin;
hl.drawPanel();
var HeaderLogin = function(elem) {
this.init = true;
this.jsvh = JSViewHandler.getInstance();
};
HeaderLogin.prototype.drawPanel = function() {
var self = this;
...
this.jsvh.get({
...
'callback': function(rsp, templates) {
...
$('#jsview_user_login_form').ajaxForm({success: asd});
}
});
function asd(rspJSON, statusText, xhr, $form) {
self.showResponse(rspJSON, statusText, xhr, $form);
}
};
HeaderLogin.prototype.showResponse = function(rspJSON, statusText, xhr, $form) {
if (typeof this.init === 'undefined') {
alert('not an object');
}
...
}
I have to call the showResponse function after the form has been sent, but if I use the {success: self.showResponse} the init will not exists. It looks like a static call and I can't access any variable from the constructor. If I create a local asd function and I use it as the success callback the showRespons will know about the constructor variables.
I don't want to use this extra function, if you have any solution about this problem, please let me know!
Thanks a lot guys! :)
SOLUTION:
success: self.showResponse.bind(self)
I have not done this in a long time, but can you try with
'callback': function(rsp, templates) {
...
var s = self;
$('#jsview_user_login_form').ajaxForm({success: s.showResponse});
}

Method for jQuery plugin

I'm trying to make a jQuery plugin for custom checkboxes and radio buttons.
(function($)
{
$.fn.checkboxRadio = function(options)
{
var defaults = some;
...
return this.each(function()
{
var button = $(this);
...
});
}
})(jQuery);
It can be used now by $('input').checkboxRadio(options);
How do I add a method check without changing current scope, to make a possible usage of something like $('input').checkboxRadio('check')?
How to handle a custom method and get its name inside my plugin?
Here is the official jquery plugin guide.
The part about wrapping functions is found here ("Plugin Methods") (the example is a would-be tooltip plugin) :
(function( $ ){
var methods = {
init : function(options) { ... },
show : function() { ... },
hide : function() { ... },
update : function(content) { ... }
};
$.fn.tooltip = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.tooltip' );
}
};
})(jQuery);
[update] explaining the methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )) line in the guide :
If you call $(selector).tooltip('update', 'hello') from your javascript code, you want to end up calling the update method, passing 'hello' as the content argument, with this set to $(selector) for the duration of the call.
That is what this line takes care of :
if method == 'update', methods[method] is the update method,
arguments will be equal to ['update', 'hello'], you have to drop the first element to get the arguments you want to pass to your method ; this is exactly what Array.prototype.slice.call(arguments, 1) does,
myFunc.apply(obj, argsArray) calls the function myFunc, passing argsArray as the arguments, and setting this to obj for the duration of the call.
So inside your methods, you can call this.each(...) to iterate over all of the selector's items, e.g. :
update: function(content) {
this.each(function(){ $(this).data('tooltip.content', content); });
return this;
}
You can connect plugin methods like this:
(function($) {
$.fn.checkboxRadio = function(options) {
var defaults = {
check: 'check'
}
return this.each(function() {
var o = options;
var _this = $(this);
if( o.check === 'check' ) {
_this.attr('checked','checked');
}else if ( o.check === 'uncheck' ) {
_this.removeAttr('checked');
}
});
}
})(jQuery);
and user document should be like what you want: $('input').checkboxRadio({check:'check'});

JavaScript/jQuery: Use 'this' Object on Success

I have a somewhat annoying issue when it comes to sending an Ajax request to a server and then returning the data on the success function within an JavaScript object. I've searched for similar questions, but none were really of the same manner as mine.
For example, I have the following code for sending a request within an object:
function SomeObject ( someVar )
{
var someVar = someVar;
}
SomeObject.prototype.sendRequest = function ()
{
$.ajax(
{
url : "somePage.php",
type : "POST",
data :
{
someVar : someVar
},
success : this.parseSuccess
} );
};
SomeObject.prototype.parseSuccess = function ( data )
{
if ( data === "success" )
{
this.proceed(); // Error
}
else
{
alert( "Server failed request." );
this.proceed();
}
};
SomeObject.prototype.proceed = function ()
{
// Do something else
};
I know that this.proceed() will fail because this is not the SomeObject instance.
Still, how can I efficiently refer back to the object after the request is complete?
I found I could do the following to achieve what I want, but it does not feel proper, and I would like a better way to handle the Ajax calls:
SomeObject.prototype.sendRequest = function ()
{
var me = this;
$.ajax(
{
url : "somePage.php",
type : "POST",
data :
{
someVar : someVar
},
success : function ( data )
{
me.parseSuccess( data ); // Will work
}
} );
};
Thanks for any help on the matter.
You could always do this:
success : function ( data )
{
parseSuccess.apply(this, [data]); // or parseSuccess.call(this, data);
}
Basically, with apply(), you can pass in the context of this you want to use inside the function, which in this case is the SomeObject context.
You can use the context option of $.ajax. Specifically, using context: this will set the this value inside parseSuccess to the current this value, which is what you want.
$.ajax({
// ...
context: this,
success: this.parseSuccess
});

Custom jQuery function - selector doesn't find element

I'm playing around with making a REST api and I'm working on some javascript functions.
The idea here is to run for example: $('#main').get('car/ford'); and the data returned will be added in the element provided.
Here is all the javascript:
$.fn.extend({
get: function (path) {
request(this, 'GET', path);
}
});
function request(element, type, path) {
var dees = $(element);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
a = $(element);
b = $('#fileList'); // this is a control
dees.html(data);
}
});
}
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
The problem I'm having is that when I run a.html(data);
Nothing will change. But if i run b.html(data);
Everything works like it should.
So there is a difference between those two selectors.
On a the element is not found a.length == 0
and on b the element is found b.length == 1
Why isn't the element found by the selector and how can I fix it?
The problem was solved by adding $ in front of the calling function.
From:
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
To:
$(function() {
console.log('running');
$('#fileList').get('car/ford');
});
You could try the following:
function request(element, type, path) {
var dees = $(element);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
dees.html(data);
}
});
}
in case the $(this) variable is conflicting with own $(this) variable of ajax() block.
Change element to $(element)
When request is call request(this, 'GET', path); this represents javascript object and it should be jQuery object. You need to pass jquery object or convert it to jquery object after being pass as I did.
$.fn.extend({
get: function (path) {
alert(this.tagName);
var objToPass = $(this);
request(objToPass, 'GET', path);
}
});
function request(javascriptObj, type, path) {
element = $(javascriptObj);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
a = $(element);
b = $('#fileList'); // this is a control
a.html(data);
}
});
}
Update
The call to get function should be instantiated on document.ready which could be done by simply adding $
Change
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
To
$(function() {
console.log('running');
$('#fileList').get('car/ford');
})();

Categories