This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I need to pass outside variable to jQuery Ajax's success-function. My ajax is in a loop like so:
var props = ['a', 'b', 'c'];
var results =
{
a: null,
b: null,
c: null
};
for(var key in props)
{
var prop = props[key];
$.ajax(
{
url: 'someurl',
data:
{
somedata: 'somevalue'
},
success: function(data, status, xhr)
{
// This here does not work properly, because the prop's value changes
// Due to promise stuff
results[prop] = data;
}
});
}
I need to stuff the data returned in success in to the correct place, but the implementation above does not work because the value of prop changes before the success is called.
I found out that I can "bypass" this problem by binding the success-function's this with the prop like so:
success: function(data, status, xhr)
{
results[this] = data;
}.bind(prop)
But this does not seem like a very good idea and besides, I can only bind one variable, not multiple if need be.
This does not seem to work either:
success: function(data, status, xhr)
{
var privprop = prop;
results[privprop] = data;
}
So basically what is the best way to give each success callback a "private" variable, which value is what the value of prop was when the whole ajax was made? Can I somehow bind multiple variables and overwrite something else than this?
Try to limit the scope of every prop variable for a specific ajax by doing something like this:
for(var key in props)
{
var prop = props[key];
(function(prop){
$.ajax(
{
url: 'someurl',
data:
{
somedata: 'somevalue'
},
success: function(data, status, xhr)
{
// This here does not work properly, because the prop's value changes
// Due to promise stuff
results[prop] = data;
}
});
})(prop);
}
Related
Please refer the below example code
var report = {
chartTypes : null,
init: function () {
this.getChartTypes(function(data){
this.chartTypes = data;
});
},
getChartTypes: function(callback) {
$.ajax({
data:'',
url:'',
success:function(response){
chartTypes = JSON.parse(response);
callback(chartTypes);
}
});
},
getToolbar:function() {
this.chartTypes --------------- NULL
}
}
getChartTypes function load different chart types via AJAX. Therefore i put it as a callback function. Data is received successfully. But when i use this.chartTypes in a different function like getToolbar it says this.chartTypes is null. Even i have initialized the same in the starting. May be scope issue. Please advise.
You are assigning to a variable (probably global) called chartTypes, but that isn't the same as reoprt.chartTypes. You need to assign to this.chartTypes, but this in your anonymous function won't be the same as this outside it, so you need to remember that value using another variable:
getChartTypes: function(callback) {
var self = this;
$.ajax({
data:'',
url:'',
success:function(response){
callback( self.chartTypes = JSON.parse(response) );
}
});
}
With an OOP approach, most developers would use a method and use .bind() to maintain the proper scope when the asynchronous success method is triggered. This way you do not have to worry about closures and using variables to hold the scope of this.
var report = {
chartTypes : null,
init: function () {
this.getChartTypes();
},
getChartTypes : function(callback) {
$.ajax({
data:'',
url:''
}).done(this._setSuccessResponse.bind(this));
},
_setSuccessResponse : function(data){
this.chartTypes = data;
},
getToolbar : function() {
console.log(this.chartTypes);
}
}
You also need to make sure that when you call getToolbar that the Ajax call has also been completed.
First of all: I don't know exactly how to call everyting since I am quite new to the more OOP way of writing javascript, so I'll try to explain everything as good as possible.
My problem is that I want to access properties inside an object ( so I can use the this-keyword. This works fine as long as I am in the scope of the object. When I go outside the scope, I would like to access those properties while I can't use the this-keyword anymore.
My code:
var Octa = Octa || function () {
this._initialize();
};
Octa.prototype = {
string: 'Foo',
_initialize: function () {
console.log(this.string); //Output: "Foo"
this.othermethod();
}
}
var Octa = new Octa();
But when I have a method within an Octa method, so outside the scope where I can't use this anymore to get Octa's properties, I can't reach the properties within Octa.
For example:
othermethod: function () {
$.ajax({
url: this.globalUrl + 'content/language/lang.' + l + '.php',
data: {
ajax: true
},
dataType: 'json',
success: function (response) {
Octa.lang = response;
}
});
console.log(JSON.stringify(this.lang)); //Output: null, which means Octa.lang wasn't reachable in the ajax success event (the ajax request was successful).
}
Is there a way to reach the scope of Octa within other objects? Or within jQuery callbacks since the same problem occurs there.
I hope my problem is understandable and if not, I'll try to give more clarification.
Simply refer back to this inside the function scope:
...,
someMethod: function () {
var self = this,
ajaxOptions = this.settings.ajaxOptions;
// note we can still refer to 'this' at this level
$.ajax(ajaxOptions).done(this.ajaxDone).fail(this.ajaxFail);
// the function scope changes for the deffered handlers so you can access by reference of 'this' => self
$.ajax(ajaxOptions).done(function(data, status, xhr){
self.ajaxDone(data, status, xhr)
}).fail(function(xhr, status, error){
self.ajaxFail(xhr, status, error);
});
},
ajaxDone: function(data, status, xhr) {},
ajaxFail: function(xhr, status, error) {},
...
Hope this makes sense.
Now there's also a .bind() function that can be used to bind function scope to a parameter:
$.ajax(ajaxOptions).done(function(){
this.ajaxDone();
}.bind(this));
You'll have to use a polyfill to support older browsers. It's much more easier to use var self imho.
I have an AngularJS factory method that is setting properties like this (specifically in the getPageInformation method):
function factoryMethod($http, $q) {
return function(id) {
return {
id: id,
getPageInformation: function() {
var deferred = $q.defer();
$http({
method: "post",
url: 'getInfo.php',
data: {
id: this.id
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function(successResponse) {
console.log(successResponse);
deferred.resolve('Fetched');
for (var attr in successResponse.data) {
this[attr] = successResponse.data[attr];
}
}, function(errorResponse) {
console.log(errorResponse);
deferred.reject('Unable to fetch');
});
return deferred.promise;
}
}
}
}
The problem is not with AngularJS, as you can see I am returning and object (from the curly braces syntax), but I need to be able to dynamically set the object properties. I did a loop through the appropriate info I got from the response, but it isn't setting it:
for (var attr in successResponse.data) {
this[attr] = successResponse.data[attr];
}
Instead, I think the problem is that (when I console.loged this it brought me the entire browser window object), this is failing to refer to the current instance. Is there any I can achieve what I'm doing or is this how it should be working and there is another problem?
The meaning of the this variable in Javascript is a pain. You can try searching online for the gory details. For this question I believe it suffices to say that this in callbacks is most probably not what you intuitively expect. You need to create a closure with the real this, commonly done as:
return {
...
getPageInformation: function() {
var self = this; // The closed variable here
...
$http({...})
.then(function(successResponse) {
...
for (var attr in successResponse.data) {
self[attr] = successResponse.data[attr]; // Use like this
}
...
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
How to return AJAX response Text? [duplicate]
(2 answers)
Closed 8 years ago.
initialize: function() {
var store = {};
var item = {};
var me = this;
Ext.Ajax.request({
url: "some_valid_url",
success: function(response) {
try {
var parser = new DOMParser();
var xml = parser.parseFromString(response.responseText, "text/xml");
store = Ext.create('Ext.data.Store', {
autoLoad: true,
fields: ['temp', 'low', 'high', 'desc', 'icon'],
data: xml,
proxy: {
type: 'memory',
reader: {
type: 'xml',
rootProperty: 'current',
record: 'day'
}
}
});
item = Ext.create("Ext.Container", {
var bla = "hello world",
})
} catch (err) {
//err
}
}
});
}
console.log("STORE AND ITEM");
console.log(item);
console.log(store);
Why item and store give back null objects?
However I can see that it's parsing some data, as if I put console.log in between store and item elements I will get a valid element.
STORE AND ITEM
Object {} ArticleWeatherList.js:105
Object {} ArticleWeatherList.js:106
Ajax is asynchronous which basically means that the code continues executing without waiting for the request to complete. Therefore, when you are trying to use item and store, the request has not yet completed and the success method which sets them has not yet run. The only ways round this are to force the request to happen synchronously (although this is generally a bad idea) or to put all the code that depends on the request into the success callback or functions that are called from within the success callback.
Because,
you have declared store and item as local variables inside intialize function. If you want access these variable outisde you must declare them in the global not in the function. The same can be achived omitting the var keywords in the declaration of the variables.
initialize: function () {
store = {};
item = {};
var me = this;
....
this should works but is a considered a bad practice.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
$.ajax context option
I've got some code that looks like this:
$.post(self.baseUrl + 'api/method',
{param1: data},
function (response) {
// Do something
});
I want to pass a reference to the self object through to the callback, which I imagined would be something like this:
$.post(self.baseUrl + 'api/method',
{param1: data},
function (response, self) {
// Do something
});
However, it doesn't work like this, the jQuery documentation doesn't show a way that would make this possible and a cursory Google search hasn't turned up anything. Is this possible, and how can I do so?
If you use the $.ajax method you can specify a context:
$.ajax({
type: "post",
context: self,
data: {param1: data},
success: function (response) {
console.log(this); // now 'this' refers to self
}
});
#karim79 shows the best solution. I just want to show some other possible ways
var App = {
baseUrl: "http://.../",
fetchData: function() {
var self = this;
$.post(self.baseUrl + 'api/method', {
param1: data
}, function(data) {
self.onDatafetch(data);
//or
globalDataFetch(data, self);
});
},
onDatafetch: function(data) {
this.showMsg();
},
showMsg: function() {
alert("Success");
}
}
App.fetchData();
function globalDataFetch(data, object){
// received data and object
}
why do you want to do sth like that?
you could easily use a closure:
var param1 = data;
$.post(self.baseUrl + 'api/method', function (data) {
// access param1 here
});