jQuery Async Issue, Variable Assignment After GET Request - javascript

I'm sure the solution is staring me right in the eyes, but I just cannot see it. I am trying to load an object from an outside file source. I've tried it several which ways using jQuery's built in methods, but keep returning undefined. Is my issue the scope? I need partnerData right where it is because of other dependent methods in my script. I don't want to operate the rest of my site's functions from within the $.get callback. Any help is greatly appreciated, here's the code:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
});
console.log(partnerData); /* returns undefined instead of object */
});
EDIT:
Thanks for all the feedback everyone. This is the solution I went with:
var partnerData;
$.ajax({
url: 'data/partners.json',
dataType: 'json',
async: false,
success: function(data) {
partnerData = data;
}
});

The reason why you're seeing undefined is because ajax requests are asynchronous by default. This means your get method gets invoked and the code flow moves down to the next statement while the request executes in the background. Your callback function is later invoked when the request completes.
Using callback functions is a common pattern used in situations like this. But you seem to be saying you don't want to do or can't do that. In that case, you could use async: false which would force the request to be synchronous. Keep in mind however, that your code will be blocked on the request and if it's a long-lived request, the user experience will degrade as the browser will lock up.
P.S. You shouldn't need to parseJSON - if response has the correct mime-type set, jQuery will intelligently guess the type and parse the JSON automatically. And in case the server isn't sending back the correct mime-type, you can also explicitly tell jQuery what the expected return data type is; see the dataType argument to $.get() .
One way you might modify your code, to force synchronous requests:
$.ajax({
type: 'GET',
url: 'data/partners.json',
success: function(file){
partnerData = $.parseJSON(file);
//ideally you would perform a callback here
//and keep your requests asynchronous
},
dataType: 'json',
async: false
});

function is proccessed to the end event when ajax is still being proccessed. insert it into callback function
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
console.log(partnerData);
});
});

I would say that your problem is the same of the one that I just solved, if $.get is AJAX! and it is setting a variable, to read that variable outside the callback you need to wait the response! So you have to set async=false!

console.log in synchronous and get is async.
try:
$(function() {
var partnerData;
$.get('data/partners.json', function(file) {
partnerData = $.parseJSON(file);
test();
});
function test(){
console.log(partnerData);
}
});

Related

Ajax and scope problems

I'm having some problems with AJAX and the scope of my data. I am new to Javascript and I'm not sure how to fix my problem.
var urlList = new Array();
$.ajax({
url: "http://localhost:3000/url",
success: function(data) {
alert(data.expressions.url); //This shows the correct result
urlList[0] = obj.expressions.dom;
}
});
alert(urlList[0]); //this shows undefined
I need the data that is in urlList[0] so i can use it at a later time. I think it's a scope problem.
Could someone point me in the right direction please?
Thanks
It's not a scope problem, but a timing problem. The ajax method is executed asynchronously. That means that calling it will not cause your program to wait until it is finished. This results in the alert being shown before the request is finished.
To fix this, put the request inside the success function as well. This is the proper place to handle the results of the request.
var urlList = new Array();
$.ajax({
url: "http://localhost:3000/url",
success: function(data) {
alert(data.expressions.url); //This shows the correct result
urlList[0] = obj.expressions.dom;
// This might work now, depending on what `obj.expressions.dom` is. This
// isn't becoming clear from your code. Usually you would use the `data`
// parameter of the success function, which contains the response body of
// the ajax request that has just finished.
alert(urlList[0]);
// of course you can call other functions as well. For instance, you
// could call
urlListChanged();
// ..which you can declare in global scope. This way, you can repond to
// changes from multiple sources, without having to duplicate code.
// It will all work, as long as you use the success handler as the trigger.
}
});
function urlListChanged()
{
alert(urlList[0]);
}
Your problem is one of chronology.
$.ajax fires an asynchronous request, meaning the rest of your code after it will continue to be executed before the request has resolved. Since urlList is populated only once the request resolves, your alert is firing too early.
Change
$.ajax...
to
var req = $.ajax...
and wrap your alert in a success callback:
req.done(function() { alert(urlList[0]); });
...or just move the alert inside your existing success callback.

How to extract ajax response data from the success callback

Sorry if this is a duplicate but I couldn't find any satisfying answers in the previous posts.
$(function() {
$.ajax({
url: 'ajax/test.html',
success: function(data) {
// Data received here
}
});
});
[or]
someFunction() {
return $.ajax({
// Call and receive data
});
}
var myVariable;
someFunction().done(function(data) {
myVariable = data;
// Do stuff with myVariable
});
The above code works just fine. However, this ajax request is made on page load and I want to process this data later on. I know I can include the processing logic inside the callback but I don't want to do that. Assigning the response to a global variable is not working either because of the asynchronous nature of the call.
In both the above ways, the 'data' is confined either to the success callback or the done callback and I want to access it outside of these if possible. This was previously possible with jQuery 'async:false' flag but this is deprecated in jQuery 1.8.
Any suggestions are appreciated. Thank you.
You can "outsource" the callback to a normal function, so you can put it somewhere, you like it:
$(function() {
$.ajax({
url: 'ajax/test.html',
success: yourOwnCallback
});
});
somehwere else you can define your callback
function yourOwnCallback(data) {
// Data received and processed here
}
this is even possible with object methods as well
This solution might not be idea but I hope it helps.
Set the variable upon callback.
Wherever you need to process the data, check if variable is set and if not wait somehow.
Try:
$(document).ready(function(){
var myVar = false;
$.ajax({
url: 'ajax/test.html',
success: function(data) {
myVar=data;
}
});
someFunction(){ //this is invoked when you need processing
while(myVar==false){}
... do some other stuff ..
}
});
Or
someFunction(){
if(myVar==false){
setTimeout(someFunction(),100); //try again in 100ms
return;
}
.. do some other stuff ..
}

Returning the Result of a $.getJSON-Function

I need to load a php-script with ajax, which creates a JSON-result.
An example of the getEvent.php is:
[{"id":"1","start":"Wed Jul 18 12:00:00 GMT+0200 2012","end":"Wed Jul 18 13:30:00 GMT+0200 2012","title":"leer"}]
In order to transmit this result to another function, I have to be able to assign it to an variable. I tried it many ways, but it has never worked out.
function loadEvents(){
var cdata;
$.getJSON({
type: 'GET',
url: 'getEvent.php',
asynch:false,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(jsonData) {
cdata = jsonData;
},
error: function() {
alert('');
}
});
return cdata;
}
cdata = jsonData; doesnt seem to work
I have only found ways to asign parts of the result (jsonData) to a variable, but it seems that the entire jsonData can't be returned.
Can anybody help me with my problem? I have to return the complete jsonData to another function...
Thanks
getJSON is an asynchronous function (expectiong just a url, no settings object (Docu)), meaning that it will return a result as soon as the answer from the server is done. In the meantime your function continues execution. Thus, at the moment you return cdata, your success function hasn't executed yet. You need to either use a callback or set the function to be synchronous (which you are trying to do but have a typo in there - it's async without h - also if you want to pass additional settings, you can't use getJSON() but have to use $.ajax().
instead of making the call synchronous, using the callback is probably the better solution:
instead of
success: function(jsonData) {
cdata = jsonData;
},
write:
success: function(jsonData) {
workWithResult(jsonData);
},
// this is called the "callback" function, it is executed when the ajax-request
// returned successfully
function workWithResult(data){
// now you can work with the data, which is guaranteed to exist
}
First thing, why are you using getJSON?
$.ajax seems to suit more to your requirement.
Second,
The moment you return the cdata comes before the server responds. Your success handler will be executed once the server responds. In the current case, you won't be getting the data you are looking for. :)
What you can do to get around with this is to make the variable cdata global.
And just assign the value to cdata in success handler (which you have done already)
PS : Making variables global is not a good programming practice. (Or at least I don't recommend making use of global variables)
Post your specific requirement, like in what way you are going to use the returned value. So that we can see how we can avoid that global beast.
for eg:
success: function(result){
yourTargetFunction(result); // call the target function with returned data as a paramenter to it
}

Asynchronous callbacks

I've written a function which makes an asynchronous request using jQuery.
var Site = {
asyncRequest : function(url, containerId) {
$.ajax({
url : url,
onSuccess: function(data){
$(containerId).html(data);
}
});
}
}
Syntax might be slightly wrong as I'm using notepad, but hopefully you get the idea.
I call the function:
Site.asyncRequest('someurl', container1);
Site.asyncRequest('someurl', container2);
Both requests get sent and processed by the server. Two responses get sent back, which is what I expect. However, I would expect container1 and container2 to contain responses from both requests.
The problem, is that only the last response gets displayed and I can't figure out why. I don't know how the jQuery ajax keeps a track of requests/responses, so maybe this is a problem.
Say I make 5 or 10 requests, how does jQuery ajax know which response is for which request and where does it keep a track of it?
Thank you
This appears to be a Javascript scoping issue. Try the following:
var Site = {
asyncRequest: function(url, containerId) {
(function(theContainer) {
$.ajax({
url: url,
onSuccess: function(data) {
$(theContainer).html(data);
}
});
})(containerId);
}
};
This creates a separate scope for each function call, so the actual value pointed to by "theContainer" is different for each onSuccess anonymous function.
What is happening here is a single closure is getting created, due to the way that function is declared. See "A more advanced example" here: http://skilldrick.co.uk/2010/11/a-brief-introduction-to-closures/
Basically, the containerId is being shared among all instances of that onSuccess anonymous function. I haven't tested this, but I believe if you defined your asyncRequest function outside of Site, this would work.
As far as a more elegant solution to this problem, perhaps someone else will answer better.

fetching a url using $.getJSON and parsing it correctly

This is probably really stupid but i can't find the problem with my code. It fetches a url that returns json and the function is then supposed to return a string:
function getit() {
var ws_url = 'example.com/test.js';
var user = false;
$.getJSON(ws_url, function(data) {
alert('user '+data.user);//shows john
user = data.user || false;
});
return user;//should return john but returns false
}
test.js will have something like this:
{"id":"12","username":"ses","user":"john","error":""}
or like this:
{"error":"123"}
I also tried if (data.user) {} else {} but it didn't work either..
So what am i missing?
Thanks :)
The problem comes from the fact that the $.getJSON() call is asynchronous. Once the ajax request is fired off, processing continues on inside getit(), and your function immediately returns false. Later on, the Ajax response returns and sets user, but your getit() function returned a long time ago!
You can force the Ajax call to be synchronous using the async option, like this:
$.ajax({
async: false,
url: ws_url,
type: "GET",
success: function(data) {
alert('user '+data.user);//shows john
user = data.user || false;
}
});
If you do that, your browser will block on the script until the Ajax call returns. Generally this isn't the ideal behaviour (which is why the default is async: true), so I'd suggest reworking whatever it is that's calling getit(), and have it expect to process it's results whenever it can, perhaps by passing it's own callback function to getit() that would then be executed when getit() is done.
Ajax is asynchronous, which means that the rest of the script isn't going to sit around and wait for it to finish before moving on. As in your example, the return line is being reached before the ajax function receives a response from the server, thus the user variable is still false at that point in time.
If you want to force an ajax call to run synchronously, you can use jQuerys $.ajax method and set the async parameter to false.
$.ajax({
url:ws_url,
dataType:"json",
async:false,
success:function(data){
alert('user '+data.user);//shows john
user = data.user || false;
}
});

Categories