Reputation: 366
I'm dealing with a problem about an Ajax callback inside of an Object. Please consider this code :
Search.prototype =
{
ask : function( query )
{
// Display loader
$('.loader').show();
$.ajax({
dataType : 'jsonp',
type : 'GET',
url : 'http://api.deezer.com/search/track/',
data : {
output : 'jsonp',
q : query
}
}).done(function(res) {
this.loadResults( res );
// [Error] Object success has no method 'loadResult'
});
},
loadResults : function (res)
{
// Hide loader
$('.loader').hide();
console.log( res );
// doing some stuff
// ...
}
}
var search = new Search();
search.ask( 'eminem' );
I get an error Object success has no method loadResult
, which makes sense as the callback is part of an anonymous jQuery function.
But how to get my initial object instance ?
I've been trying with a var that = this; before the Ajax call, but I't won't works for the same reasons.
I don't know if it's possible to do this or if the problem comes from my code global organization. Feel free to advise me about the best practices :)
Thanks by advance.
I obfuscated some things in my code which I though it was unnecessary to post here, but I finally found out the problem a little bit earlier in my code. Sorry about that.
Here's my full code, which is now working :
define(['jquery'], function($) {
var Search = function()
{
this._keyDownTimer = 0;
this._searchDelay = 1000; // ms
};
Search.prototype =
{
// The init function that I though it was unnecessary to post here. Sorry :/
init : function()
{
$('#q').on('keydown', (function(evt) {
clearTimeout( this._keyDownTimer );
this._keyDownTimer = setTimeout( (function() {
this.ask( $('#q').val() );
}).bind( this ), this._searchDelay); /* <-- Here's the solution.
I forgot to bind `this`
to the timeout callback function,
so the `this` under all of my code
was referring to the anonymous function
of this callback. */
}).bind( this ));
},
ask : function( query )
{
// Display loader
$('.loader').show();
console.log(this); // Now `this` refers to my object :)
var req = $.ajax({
dataType : 'jsonp',
type : 'GET',
url : 'http://api.deezer.com/search/track/',
context : this,
data : {
output : 'jsonp',
q : query
}
});
req.done(function(res) {
this.loadResults(res);
});
},
loadResults : function (res)
{
// Hide loader
$('.loader').hide();
// doing some stuff
// ...
}
};
return new Search;
});
Thanks for your replies, it really helped.
Pb solved.
Upvotes: 11
Views: 14250
Reputation: 191799
There are several ways to do this.
You can set the context
setting for the ajax options:
jQuery.ajax
context
setting$.ajax({
context: this
Function.prototype.bind
.done(function (res) {
}.bind(this));
However, this is not as widely supported as...
jQuery.proxy
Created for this purpose.
.done($.proxy(function (res) {
}, this);
var self = this;
$.ajax({
/* snip */
.done(function (res) {
self.loadResults(res);
This is commonly done in JavaScript to give access to this
in lower scopes.
$.ajax({
/* snip */
.then(res => this.loadResults(res));
Upvotes: 35
Reputation: 339985
You can use the ES5 .bind
function to set this
correctly:
$.ajax(...).done(this.loadResults.bind(this));
(use the shim at the above link, or the jQuery $.proxy
equivalent on older browsers).
Alternatively, add context: this
to the $.ajax
options:
$.ajax({
...,
context: this
}).done(this.loadResults);
Note that in either case you will override jQuery's default behaviour of passing the ajax option object in this
.
p.s. it's also good practise to return
the result of the $.ajax()
chain so that the user of your object can chain additional callbacks (e.g. a .fail
handler) to it.
Upvotes: 3