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.
Related
I am trying to pass in an array of functions as a parameter to function x then execute them within the function x. I will also somehow pass in parameters but some of the parameters are only initialised within function x.
Some functions include things like:
_showData(data,type);
console.log(data);
$('#loading').remove();
Here is a sample:
// Called somewhere else
runFunctions([$('.dashboard').remove, $('.screen-loading').remove]);
var runFunctions = function(functions){
// do some things
for (var i = 0; i < functions.length; i++){
functions[i]();
}
Any ideas?
EDIT:
Sorry I just realised the program doesn't know what the objects are because I'm changing scope with an ajax call.
var runFunctions = function(functions){
$.ajax({
method: "POST",
url: "php/database.php",
dataType: "JSON",
data: {type:type},
success: function(data, type){
for (var i = 0; i < functions.length; i++){
functions[i]();
}
}
})
}
What about this:
_accessDatabase(
function(onSuccess){
$('.dashboard').remove();
var type = 'home';
_showData(data,type); // it doesn't know what data is, how can I pass it through?
$('.screen-loading').remove();
}
);
var _accessDatabase = function(onSuccess){
$.ajax({
method: "POST",
url: "php/database.php",
dataType: "JSON",
data: {},
success: function(data){
onSuccess(data);
}
})
}
I want to pass through var data to the onSuccess function, how can I do this?
Solved with:
var _request_successful = function onSuccess (data){
console.log("running onSuccess");
$('.dashboard').remove();
var type = 'home';
_showData(data,type);
$('.screen-loading').remove();
}
_accessDatabase(_request_successful);
var _accessDatabase = function(onSuccess){
$.ajax({
method: "POST",
url: "php/database.php",
dataType: "JSON",
data: {},
success: function(data){
onSuccess(data);
}
})
}
The problem with this code is that the functions that you're calling within the forLoop aren't bound to anything. Take this instead.
// Called somewhere else
runFunctions([
$('.dashboard').remove.bind($('.dashboard'))
, $('.screen-loading').remove.bind($('.screen-loading'))
]);
function runFunctions(functions){
// do some things
for (var i = 0; i < functions.length; i++){
console.log("running")
functions[i]();
}
}
What you could do instead is this:
function call(method, objs) {
objs.forEach(function (obj) {
obj[method]()
})
}
call('remove', [$('.dashboard'), $('.screen-loading')])
Here's a working fiddle: https://jsfiddle.net/ogfgocp4/
To explain a bit how it works, I don't know exactly the internal of JavaScript, but when you do: $('.dashboard').remove, it will return you the remove function. If you call it immediatly, it will be bound to the object which give you the method. If you affect it to something else, then it will be bound to the object it's being called from.
Here's a small snippet of code that explains it well I guess.
var obj = {
fun: function () {
console.log(this)
}
}
var fun2 = {
a: 1
}
//this -> obj
obj.fun()
// this -> window
fun = obj.fun
fun()
// this -> fun2
fun2.fun = obj.fun
fun2.fun()
When you call obj.fun, this will be the object obj. When you affect the method to a var, this then become window as it is the default object in this scope. Then if we finally bind the function to object fun2 and call it immediatly, this is now the object fun2.
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/
I have a very simple class, but already run into pain with the definition of ‘this’ in Typescript:
Typescript
/// <reference path='jquery.d.ts' />
/// <reference path='bootstrap.d.ts' />
module Problem {
export class Index {
detailsUrl: string;
constructor() {
$('.problem-detail-button').click((e) => {
e.preventDefault();
var $row = $(this).closest('tr'); //this must be that of the callback
var problemId: number = $row.data('problem-id');
$.ajax({
url: this.detailsUrl, //this must be the instance of the class
data: { id: problemId },
type: 'POST',
success: (result) => {
$('#details-modal-placeholder').html(result);
$('#details-modal-placeholder modal').modal('show');
},
})
});
}
}
}
Javascript
var Problem;
(function (Problem) {
var Index = (function () {
function Index() {
var _this = this;
$('.problem-detail-button').click(function (e) {
e.preventDefault();
var $row = $(_this).closest('tr');
var problemId = $row.data('problem-id');
$.ajax({
url: _this.detailsUrl,
data: {
id: problemId
},
type: 'POST',
success: function (result) {
$('#details-modal-placeholder').html(result);
$('#details-modal-placeholder modal').modal('show');
}
});
});
}
return Index;
})();
Problem.Index = Index;
})(Problem || (Problem = {}));
Now the problem is that the line
var $row = $(this).closest('tr'); //this must be that of the callback
and this line
this.detailsUrl, //this must be the instance of the class
conflict in the meaning of 'this'
How do you handle the mixture of the 'this'?
module Problem {
export class Index {
detailsUrl: string;
constructor() {
var that = this;
$('.problem-detail-button').click(function (e) {
e.preventDefault();
var $row = $(this).closest('tr'); //this must be that of the callback
var problemId: number = $row.data('problem-id');
$.ajax({
url: that.detailsUrl, //this must be the instance of the class
data: { id: problemId },
type: 'POST',
success: (result) => {
$('#details-modal-placeholder').html(result);
$('#details-modal-placeholder modal').modal('show');
},
})
});
}
}
}
Explicitly declare that = this so you have a reference for that.detailsUrl, then
don't use a fat arrow for the click handler, so you get the correct this scope for the callback.
You need to fallback to the standard way of javascript. i.e store the variable as :
var self = this;
Then you can use function instead of ()=> and use this to access variable in callback and self to access the instance of the class.
Here is the complete code sample:
module Problem {
export class Index {
detailsUrl: string;
constructor() {
var self = this;
$('.problem-detail-button').click(function(e){
e.preventDefault();
var $row = $(this).closest('tr'); //this must be that of the callback
var problemId: number = $row.data('problem-id');
$.ajax({
url: self.detailsUrl, //this must be the instance of the class
data: { id: problemId },
type: 'POST',
success: (result) => {
$('#details-modal-placeholder').html(result);
$('#details-modal-placeholder modal').modal('show');
},
})
});
}
}
}
// Creating
var foo:any = {};
foo.x = 3;
foo.y='123';
var jsonString = JSON.stringify(foo);
alert(jsonString);
// Reading
interface Bar{
x:number;
y?:string;
}
var baz:Bar = JSON.parse(jsonString);
alert(baz.y);
And your generated javascript:
var Problem;
(function (Problem) {
var Index = (function () {
function Index() {
var self = this;
$('.problem-detail-button').click(function (e) {
e.preventDefault();
var $row = $(this).closest('tr');
var problemId = $row.data('problem-id');
$.ajax({
url: self.detailsUrl,
data: {
id: problemId
},
type: 'POST',
success: function (result) {
$('#details-modal-placeholder').html(result);
$('#details-modal-placeholder modal').modal('show');
}
});
});
}
return Index;
})();
Problem.Index = Index;
})(Problem || (Problem = {}));
var foo = {
};
foo.x = 3;
foo.y = '123';
var jsonString = JSON.stringify(foo);
alert(jsonString);
var baz = JSON.parse(jsonString);
alert(baz.y);
If you're only supporting browsers that have .addEventListener, I'd suggest using that to associate your data with your elements.
Instead of implementing your code, I'll just give a simple example.
function MyClass(el) {
this.el = el;
this.foo = "bar";
el.addEventListener("click", this, false);
}
MyClass.prototype.handleEvent = function(event) {
this[event.type] && this[event.type](event);
};
MyClass.prototype.click = function(event) {
// Here you have access to the data object
console.log(this.foo); // "bar"
// ...and therefore the element that you stored
console.log(this.el.nodeName); // "DIV"
// ...or you could use `event.currentElement` to get the bound element
};
So this technique gives you an organized coupling between elements and data.
Even if you need to support old IE, you can shim it using .attachEvent().
So then to use it, you just pass the element to the constructor when setting up the data.
new MyClass(document.body);
If all the logic is in your handler(s), you don't even need to keep a reference to the object you created, since the handlers automatically get it via this.
I normally bind this to a variable as soon as I have it in the scope I want.
However the this you are after could be found like this:
constructor() {
var class_this=this;
$('.problem-detail-button').click(function (e) {
e.preventDefault();
var callback_this=e.target;
Late to the thread, but I have something different to suggestion.
Instead of:
var $row = $(this).closest('tr'); //this must be that of the callback
Consider using:
var $row = $(e.currentTarget).closest('tr');
As in this example, anywhere you might want to use this in a jQuery callback, you have access to a function parameter you can use instead. I would suggest that using these parameters instead of this is cleaner (where "cleaner" is defined as more expressive and less likely to be turned into a bug during future maintenance).
module Problem {
export class Index {
constructor() {
$('.classname').on('click',$.proxy(this.yourfunction,this));
}
private yourfunction(event){
console.log(this);//now this is not dom element but Index
}
}
}
check about jquery.proxy().
just remind you there is another way.
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
});
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');
})();