Javascript variable scope question - javascript

I am confused with the variable scope in Javascript. I am trying to load data file (.json) using Prototype library and parse the response text using json-sans-eval. The problem is it seems to me that the content from data file is lost if I tried to access "dataObj" outside of the Ajax.Request scope.
The variable in Javascript has reference count. I don't understand how can the global variable 'dataObj' will lose its data. Any hint or help?
Thank you!
var dataObj;
function OnLoadHandle() {
new Ajax.Request('data.json',
{
method:'get',
onSuccess: function(transport)
{
var response = transport.responseText || "no response text";
dataObj = jsonParse(response);
console.log(dataObj["[0,0]"]); // OK
},
onFailure: function(){ alert('Something went wrong...') }
});
console.log(dataObj["[0,0]"]); // ERROR
}

The second invocation of console.log(...) at the end of OnLoadHandle runs immediately, whereas the one inside onSuccess runs only after the request completes. The second console.log serves no purpose.
More broadly, this means that there is no point in making dataObj a global variable. It is only useful after it is assigned in onSuccess and should therefore be scoped as a local variable within onSuccess. If you need it elsewhere, onSuccess should pass it as a parameter to some other function.

Related

Javascript updating global variables and hoisting

I have a javascript function that uses an ajax function to post to a php script and a variable used to determine if the result comes back as true or false. In php, I would normally assign the function to a variable such as this:
$insert_item = $process->insert_item($item_array);
If ($insert_item->error)
{
//error detected, do something
}
I have not been able to accomplish this with javascript. Instead, I get a [object object] return if I assign a function to a variable. As a cheap alternative, I am trying to use a global variable to write any errors:
var error = false;
function update_db(formInput) {
$.post(action.php, formInput, function(data) {
if (data != 0) {
error = true
}
});
return error;
}
var updateDb = update_db(form_data);
if (updateDb) {
alert("error detected");
In this example, 'error' comes back as false despite the ajax function updating it to true. I have read all about javascript hoisting, but have yet to find a solution. Is there anyway around this? My problem stems completely from the ajax function which I have also tried accessing directly to return any vars (like I easily do in PHP) but I have had no luck!
As a side note, I find it interesting that I can access 'error' within the ajax function (returns as false) but not able to change it.

Can we save jquery POST/GET callback function's data and status in a variable for further use?

I want to save the value of data and status in a variable and use it after the closing brackets of jquery GET/POST function.But alert comes only when it is inside .get braces.
$(document).ready(function(){
$.get("demo_test.asp",function(data,status){
v = data;
});
alert("Data:"+v);
});
As Jasper said, your alert is being triggered before the request is complete (async!). So, you have two options:
Do your logic inside the callback:
$.get("demo_test.asp",function(data,status){
v = data;
alert("Data:"+v);
//Process stuff here
});
Or pass the received data onto another function and work with it there
$.get("demo_test.asp",function(data,status){
v = data;
doStuff(v);
});
function doStuff(param) {
console.log(param);
}
You're absolutely correct; the code is working as it should... here's why:
The page loads and starts running code, it then hits the .get command and then keeps running, obviously making it to the 'alert' you have next. Since the .get function is still working on fetching the data before your page makes it to the 'alert' part... there's nothing to prompt.
You might want to string things together after the .get, using deferred objects. Look into: http://api.jquery.com/deferred.always/
This is a way of tacking on another function inside of the one fetching your data, so they depend on each other.
Simple answer, yes, you can store the data in a global variable and access it elsewhere. However, you must wait until it is ready.
The better way to do it is to instead store the jqXHR globally and simply add a done callback to it when you need to access the data.
var reqDemoTest = $.get(...);
//... some time later...
reqDemoTest.done(function(data){
console.log(data);
});

Trying to understand how function call back works

I am taking jQuery.Atmosphere.js as an example, in this it has public function such as onMessage, onError etc. And when implementing this api i have done the following
var socket = $.atmosphere;
var request = new $.atmosphere.AtmosphereRequest();
request.onMessage = function(response) {
// do what i want to do
}
Here the onMessage will be trigger whenever the server pushes data to browser. I don't understand how request.onMessage(response) get notified which is outside the atmosphere api? I have looked in to the jQuery.Atmosphere.js and couldn't connect the dots how this works. I am not talking about websocket or server push or anything about atmosphere framework. I just want understand how javascript function callbacks work. Can anyone point me an example how function callbacks work or send me a link so i can dig in?
Your syntax is incorrect, it should be:
request.onMessage = function(response) {
// do what I want to do
};
As you can see, the onMessage property must be set to a function. When the Message event occurs on this object, the function will be called. The jQuery.Atmosphere.js code contains:
f.onMessage(response);
where f is its internal variable representing the AtmosphereRequest object. This function is called from invokeFunction():
function _invokeFunction(response) {
_f(response, _request);
// Global
_f(response, jQuery.atmosphere);
}
_request is a local variable in the AtmosphereRequest constructor, which contains all the state of this request object. This is part of Javascript object oriented programming; all uses of this AtmosphereRequest object have access to these internal state variables.

Retrieve variable from javascript object method callback

In my code I need to call an object method, retrieve the data from its callback, and pass it to another method or function.
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
However, the callback does not recognize any functions/objects/variables outside its scope.
What I've tried to do right now is wrap everything around a function.
var myData = '';
(function(myData) {
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
myData = data;
}
);
});
doAwesomeStuff(myData);
However that doesn't work either.
Anybody know how to properly accomplish this?
You haven't really given us enough to go on there, but this statement:
However, the callback does not recognize any functions/objects/variables outside its scope.
...is incorrect. A function has access to everything in scope where it's defined, so for instance:
var a = 10;
function foo(b) {
bar(5);
function bar(c) {
alert(a + b + c);
}
}
foo(12); // alerts "27"
Note how bar had access not only to c, but also to b (from the call to foo) and a (from the outermost scope shown).
So in your example, the anonymous function you're passing in as the callback has access to everything that's in scope where it's defined; doAwesomeStuff having been defined elsewhere presumably has access to different information, so you'll have to have the callback pass it any data it needs.
So I'm guessing your code looks something like this:
function doAwesomeStuff(data) {
// ...
}
function doSomethingNifty() {
var a = 10,
b = 20;
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
}
...and you want doAwesomeStuff to have access to a and b from the call to doSomethingNifty. If so, your only options are to pass them into it as arguments (probably best) or export them to variables some scope that doSomethingNifty and doAwesomeStuff share (probably not ideal, too much like globals).
You can bind required variables to the function passed into the async method.
Also, this SO question has a good treatment of the topic.
Your second version is not going to work at all, since you are trying to immediately access the data that are not yet available (not until the callback has been invoked.)
Your first method:
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
looks fine. Please provide more details on what is not working.
One problem could be that getSomeData() does not actually call the callback function.
doAwesomeStuff() can modify many different variables from the received data. The variables which can be accessed by doAwesomeStuff() are those that were available to it (in its scope) where it was created..

Accessing a variable whose value is set in an AJAX function

I've got a problem. I've been trying to solve the problem of how to avoid using global variables. I decided to use an object with functions on it instead, and wrote a script accordingly. However, the script won't run as expected:
GetXML: function() {
$.ajax({
type: "GET",
url: "questions.xml",
dataType: "xml",
success: function(xml) {
this.xml=xml;
$(window).trigger("canUseXML");
var docLength = $(xml).find('Question').length + 1;
alert("this really is an '" + this.xml + "' and the actual doclength is: " + docLength)//This is the first alert I mention.
} //close success
});//close AJAX
alert("yes! this is still a: " +this.xml) //This is the second alert I mention.
},
If it all ran as expected, both alerts would result in an 'object XMLDocument' (a variable declared elsewhere in this line: this.xml = null;). The first runs as expected. However, the second, outside of that function, returns value "null". Why?
Thanks, Elliot Bonneville
P.S. I've been stuck on the seemingly simple question of passing variables between functions for a week.
In JavaScript "this" always refers to the “owner” of the function executed, or rather, to the object that a function is a method of. So your first and second "this" does not refer to the same thing.
Assuming that the "success" function executes before the second alert (which it probably doesn't). You could do something like this:
GetXML: function() {
var that=this;
.
.
and then use "that" instead of "this".
Scoping.
Once you travel outside of anonymous function(xml) this.xml no longer exists.
You have two problems:
Scoping: this inside the callback is not your object with GetXML as a member. Use something like me = this; in the constructor of your object and then use me instead of this to explicitely set the value.
You callback function waits for a success of your Ajax request, but the rest of the script is going on, which is the purpose of callbacks. So, the Ajax request is made, and then you do alert("yes! this is still a: " +this.xml), while the callback has not yet been executed.
This is probably happening because ajax takes time to process. Javascript doesn't wait for one request before executing the next command, so while AJAX is being called, its trying to figure out what happened to this.xml.

Categories

Resources