Object scope. Why does this give a null object [duplicate] - javascript

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.

Related

this context in ajax data option [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I have object with data array and mark_read method, which sends PUT request to my Rails app. It looks like this in data option is not the object instance, how can I fix it?
Notifications.prototype = {
constructor: Notifications,
...
mark_read: function() {
$.ajax({
method: "PUT",
url: '/notifications/mark_read',
data: this.data.slice(0,5)
});
}
...
}
You should store "this" in a closure before trying to access it from inside of $.ajax function.
It should be something like this
Notifications.prototype = {
constructor: Notifications,
...
mark_read: function() {
var me = this;
$.ajax({
method: "PUT",
url: '/notifications/mark_read',
data: me.data.slice(0,5)
});
}
...
}
The scope for this is the mark_read function, so the context for this is whatever Notification object mark_read() is called upon.

Can I bind something else than 'this' for a function? [duplicate]

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);
}

Access javascript object created in a function

I'm making my first steps with javascript objects combined with php objects. So far everything is working fine, but I struggle to access the javascript object created in the ajax success response outside of this function.
Here is my JS code:
function settings(mannstage, stundenlohn, tags) {
this.mannstage = mannstage;
this.stundenlohn = stundenlohn;
this.tags = tags;
}
var currentSettings;
SendAjaxJsonRequest("getSettings");
function SendAjaxJsonRequest(method, jsonObject) {
jsonObject = (typeof jsonObject === "undefined") ? "none" : jsonObject;
$.ajax({
type: "POST",
url: "app/class/controller/ajax.php",
data: {
method: method,
jsonObject: jsonObject
},
success: onSuccess
})
};
function onSuccess(content) {
var response = $.parseJSON(content);
currentSettings = new settings(response.mannstage, response.stundenlohn, response.tags);
console.log(currentSettings); //Returns the object
}
console.log(currentSettings); //This is undefined
The last console.log is undefined. How can I make currentSettingsaccessible outside the onSuccess function?
Thank you!
Ajax is asynchronous, so the last console.log will be executed before the success function is called.
currentSettings is accessible outside the onSuccess function, but your last console.log call runs immediately after onSuccess is defined, which is before it's been called, so the value of currentSettings is still undefined at that point.
Maybe editing your code like this will demonstrate it:
function onSuccess(content) {
var response = $.parseJSON(content);
currentSettings = new settings(response.mannstage, response.stundenlohn, response.tags);
console.log(currentSettings); //Returns the object
afterSuccess(); // Also returns the object
}
function afterSuccess() {
console.log(currentSettings);
}

JavaScript call object method by its name [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
javascript object, access variable property name?
I'm trying to call a method of an object by its name when certain event happens - here's my code:
var imageObject = {
sendImage : function(obj) {
"use strict";
var thisId = obj.attr('id');
var thisSubmit = obj.attr('data-submit');
var thisCallback = obj.attr('data-callback');
var thisUrl = $('#' + obj.attr('data-url')).text();
new AjaxUpload(thisId, {
action: thisUrl,
name: 'thisfile',
onSubmit: imageObject.thisSubmit,
onComplete: imageObject.thisCallback
});
}
}
I would also like to pass the parameters to the submit and callback method.
At the moment nothing happens and I'm sure I'm not calling it right - could anyone explain how to achieve this?
I've also used the following for submit and complete :
onSubmit: function(file, extension) {
imageObject.thisSubmit(file, extension);
},
onComplete: function(file, response) {
imageObject.thisCallback(file, response);
}
But what I get is the error saying :
imageObject.thisSubmit is not a function
The attributes only store the name (string) of the method within the object - so it would be for instance 'uploadImage'.
TJ's answer is nearly there, except that (per the new code in your question) you need to either copy the arguments from onSubmit to thisSubmit, or use .apply() to copy them for you.
The code below uses the latter method, which avoids having to duplicate the function signature over and over:
new AjaxUpload(thisId, {
action: thisUrl,
name: 'thisfile',
onSubmit: function() {
imageObject[thisSubmit].apply(imageObject, arguments);
},
onComplete: function() {
imageObject[thisCallback].apply(imageObject, arguments);
}
});
If I've understood your question correctly, you need to use the square bracket syntax to access the properties:
new AjaxUpload(thisId, {
action: thisUrl,
name: 'thisfile',
onSubmit: function () { //Anonymous function so you can pass arguments
imageObject[thisSubmit]("myArg"); //Square brackets here
},
onComplete: imageObject[thisCallback] //Square brackets here (no arguments)
});
I'm assuming the thisSubmit and thisCallback local variables are meant to be the names of the functions that exist on imageObject.
Do both call those methods using names from those strings, and pass in arguments, you use a combination of bracketed syntax and closures:
var imageObject = {
sendImage : function(obj) {
"use strict";
var thisId = obj.attr('id');
var thisSubmit = obj.attr('data-submit');
var thisCallback = obj.attr('data-callback');
var thisUrl = $('#' + obj.attr('data-url')).text();
new AjaxUpload(thisId, {
action: thisUrl,
name: 'thisfile',
onSubmit: function() {
imageObject[thisSubmit](arg, anotherArg, etc);
},
onComplete: function() {
imageObject[thisCallback](arg, anotherArg, etc);
}
});
}
// Presumably there are more methods here, or added later...
}
you have to use call which call a function in js
onSubmit: function(file, extension) {
imageObject.thisSubmit.call(undefined, file,extension);
},
see What is the difference between call and apply?

Creating custom JavaScript object from data returned by jQuery AJAX request

I want to create a custom javascript object which contains data returned from a jQuery AJAX request, but I don't know which is the right way to do it. I was thinking maybe one way could be to include the AJAX request inside the constructor function so the object is created like this:
// Constructor function
function CustomObject(dataUrl) {
var that = this;
$.ajax(dataUrl, {
success: function (json) {
that.data = $.parseJSON(json);
}
});
}
// Creating new custom object
var myObject = new CustomObject('http://.....');
Another way may be to use a function which does the AJAX and then returns the new object based on the data from the AJAX response.
function customObject(dataUrl) {
// Constructor function
function CustomObject(data) {
this.data = data;
}
$.ajax(dataUrl, {
success: function (json) {
var data = $.parseJSON(json);
return new CustomObject(data);
}
});
}
// Creating new custom object
var myObject = customObject('http://.....')
I would like to know what is the best practice when doing something like this, as well as advantages/disadvatages of different methods. Maybe you can point me to some article or example on something similiar to what I am trying to do.
Thanks in advance.
I think this would be a better approach, it makes your CustomObject only knowledgeable about the data it contains. Here you delegate the work of creating objects to a factory, and pass in a callback to get a reference to the created object, since ajax is asynchronous. If you don't mind making it synchronous, then the createCustomObject function can just return the instance, and the callback can be removed.
function CustomObject(data) {
this.data = data;
}
var factory = (function(){
function create(dataUrl, objectClass, callback){
$.ajax({
url: dataUrl,
success: function (data) {
callback(new objectClass(data));
}
});
}
return{
createCustomObject: function(dataUrl, callback){
create(dataUrl, CustomObject, callback);
}
};
})();
// Creating new custom object
var myObject = null;
factory.createCustomObject('http://..', function(customObject){
myObject = customObject;
});
I'd argue that the second method is better because then you only create a new CustomObject once the script is actually fully prepared to do so (i.e. it has the data it needs from the AJAX request).

Categories

Resources