How to use and reuse JS variables across functions - javascript

I have a situation where I need to initialize/assign variables from the results of a jQuery AJAX call, and then re-use those variables further on down the script:
var shouldRedirect = ???
$.ajax({
url: 'http://example.com',
type: 'GET',
data: 'blah',
asynch: false,
timeout: 1800,
success: function(data) {
shouldRedirect = data.rows[0].redirectFlag
}
});
if(shouldRedirect)
window.location = "...";
Two issues I'm having:
Assuming the resultant JSON will contain a redirectFlag boolean, is data.rows[0].redirectFlag the proper way of obtaining the value for my variable?; and
What do I initialize shouldRedirect to before the AJAX is kicked off (how do I say "create a variable but don't give it a value yet!")?
Thanks in advance!

You can declare uninitialized variables by simply doing the following:
var shouldRedirect;
If your logic requires it you can of course initialize it to false:
var shouldRedirect = false;
This might not be what you desire though. You can check if a variable was initialized by strictly comparing it to undefined:
if (shouldRedirect === undefined) // do something
Note though, that you must use the triple equal operator (aka strict equality) or your results will not be as expected. On the other side, an undefined variable will yield a falsy result. This means that when checking a variable with a simple if (shouldRedirect) and the variable is undefined then it will yield false, as if it was set to false. This is also true for a couple of other values in JavaScript, eg the empty string "" or the value null. You can see a complete list of falsy values here. If you want to check explicitly for true or false and want to omit other falsy or truthy values, then you should check with triple equality, eg if (shouldRedirect === true).
Also, if data.rows[0].redirectFlag is the correct way to access the value is highly dependend on how the data structure you receive from your AJAX call actually looks like. If it is something like the following it would be correct:
{ rows: [ {redirectFlag: true}, {redirectFlag: false} ] }
If your JSON looks like the following though
{ redirectFlag: false }
then you have to access redirectFlag simply with data.redirectFlag.

What do I initialize shouldRedirect to before the AJAX is kicked off (how do I say "create a variable but don't give it a value yet!")?
You could just do: var shouldRedirect;
However, I would do var shouldRedirect = false; to ensure shouldRedirect is not undefined
Is data.rows[0].redirectFlag the proper way of obtaining the value for my variable?
Depends what you send back from the AJAX request. Usually responses are in JSON so if you send a JSON object back with a value true then you could do:
shouldRedirect = data.redirectFlag;

For part #1 to declare a variable with it having a value use:
var shouldRedirect. This way you can just do a if (!shouldRedirect) {}.
For part #2. How to get the value from redirectFlag is based on the formation of the data returned from the ajax call. data... would be the starting point for you to get the value.

As mentioned in the comments section, setting the shouldRedirect flag isn't going to help as the if statement that follows the $.ajax request will be evaluated before the result is fetched from the server - this is a common problem faced in asynchronous code execution. Although you can, in theory, force jQuery.ajax into syncronous mode via the sync parameter, I wouldn't recommend doing so as it will lock up the browser UI whilst the request is made.
You need to move your redirection code into the $.ajax success function like so:
$.ajax({
url: 'http://example.com',
// ... other options omitted for brevity
success: function(data) {
// This code block gets executed when the operation completes.
var shouldRedirect = data.rows[0].redirectFlag
if (shouldRedirect) {
// Your redirection code goes here.
window.location = "...";
}
}
});
If you using of jQuery 1.7 or greater, you can make use their Promises/A implementation via the defered object. Defered object's allow you to execute one or more functions when an operation completes and makes the async code easier to read.
$.ajax({ url: 'http://example.com' })
.done(function(data) {
// This code block gets executed when the operation completes.
});
Instead of passing a function closure to done, you can also pass a reference to a member function, eg:
$.ajax({ url: url }).done(onDataLoaded);
function onDataLoaded(data) {
// This function gets called when the ajax operation completes.
}

Related

JSON.parse not working with JSON string returned from an AJAX call

I have a piece of JavaScript that gets data from a backend with an ajax call. There is a JSON string returned and I cannot work out why the JSON.parse is not working.
Here is my code
var success_get = (jQuery).ajax({
url: "<?php echo base_path(); ?>reservation/success_get",
method: "GET",
async: "true"
});
In Firefox I look at the console and I see the JSON returned for success_get is
{"Reservations":[{"Id":"415b68e9-1209-4ca9-9f6b-47116ced1769","ExtraDuration":0,"TotalDuration":1,"CreationTime":"2016-02-08T00:22:59+11:00","ExpiryTime":"2016-02-08T00:32:28+11:00","Sender":{"ReturnOption":"Dispose","ReturnAddress":null,"Id":"044bf5b5-95cd-44d1-a22a-8070b45a26ba","FirstName":"Test","LastName":"User","Email":"web#tz.net","Phone":"85112366"},"Recipient":{"Id":"b53ad6ac-9750-44c8-9bdd-581e89d3be93","FirstName":"Test","LastName":"User","Email":"test#test.com","Phone":"12345678"},"KioskCode":"Hm1","LockerSize":"Small","LockerNumber":"I5","Total":4.5}],"TotalAmount":4.5,"Sender":{"ReturnOption":"Dispose","ReturnAddress":null,"Id":"044bf5b5-95cd-44d1-a22a-8070b45a26ba","FirstName":"Test","LastName":"User","Email":"web#tz.net","Phone":"85112366"},"NumberOfHoursForDropOff":47}
And that looks like valid JSON as far as I can tell
I am then doing the following
success_get.done(function( success ) {
object_rsuccess = JSON.parse(success);
console.log(object_rsuccess);
});
In Firefox I get the error
ReferenceError: object_rsuccess is not defined
However in the console.log I am seeing
Object { Reservations=[1], TotalAmount=4.5, Sender={...}, more...}
And when I expand the sections in braces I am seeing the data I would expect to see.
I would have thought that I could see the variables, eg TotalAmount by doing the following
var totalamount = object_rsuccess.TotalAmount;
But this will not work while I am getting the error for object_rsuccess not defined.
Am I missing something or simply making a silly mistake?
Wrap your code which will use the object_rsuccess in a function:
var theFunctionToBeCalled = function(obj){
var totalamount = obj.TotalAmount;
console.log(totalamount);
};
Then call it within the .done():
success_get.done(function(success) {
var object_rsuccess = JSON.parse(success);
console.log(object_rsuccess);
theFunctionToBeCalled(object_rsuccess);
});
Your AJAX settings makes the function async, which means the rest of your code continues to be executed and even when you define object_rsuccess globally, it will most probably not be available for use when you need it.
Alternative to my suggestion, based on what feels comfortable to you, you can put everything using object_rsuccess within the .done() or change async:true to async:false.

Why isn't this ajax returning the expected javascript

I have the following code:
var statusCheckUrl = "https://www.mydomain.com/webchat/live?action=avail";
$.ajax({
crossDomain: true,
dataType: "script",
url: statusCheckUrl,
success: function(result) {
console.log("result is: "+result);
eval(result);
},
error: function (jqXHR, textStatus, msg) {
unavailable();
},
timeout: 2000,
cache: false
});
If I access the url: https://www.mydomain.com/webchat/live?action=avail in my browser, the response looks like this: var isAvailable = true;
However, my console.log is printing out undefined which is obviously not working as expected.
I am running this code from localhost but thought that the crossDomain: true would overcome any cross domain issues?
How can I resolve this and why is it returning undefined in my success function?
EDIT: I have tried what the person below suggested with regards to the eval but it seems that the result value is always undefined, no matter what. Why am I getting undefined as a result of this ajax call?
The problem is not in the AJAX call, but instead that eval runs in its own scope. The var keyword in the downloaded script is setting a local variable which quickly goes out of scope. Instead you want to set a global variable (remove the var keyword).
See also: Using eval() to set global variables
Side comment: Don't execute code you don't have to, especially dynamically and cross-domain. If all you want to do is get a value - in this case if something is available or not - just return the value. (If you're not in control of the script, but it always looks the same, you could always parse it as a string. You may want to write a script which runs at some interval to check and alert you of any changes in their response format, however.)
Best practice for cross-domain requests is to make your request in your server side framework (.net, php), parse the info and get what's needed, then use your own response (json, text, whatever) back to the page.
As #Ic. said, you shouldn't be executing the code. Decent security risk there.

How to access variable inside a block

I have an AJAX request:
var foo = [],
parse = '';
$.ajax({
type: "GET",
url: "some/path/",
data: somedata
}).done(function( data ){
$.each(data.item, function(i, value){
foo.push(value);
});
parse = foo.join(', ');
});
Now the string parse is the data that I want. How can I access that data? I tried showing it using alert(), but it's not displaying anything. I think this has to do with the variable scope.
How can I get that data?
parse looks like a global variable so it will be available anywhere. The issue is probably when you're trying to access it. You can ONLY access parse in your .done() handler or some function you call from that.
The reason for this is that your ajax call is asynchronous. That means that the operation starts, the rest of your javascript continues to execute and then SOMETIME LATER the ajax call completes and ONLY then is the parse variable valid. Because of this, there really is no reason to declare the parse variable the way you have. You should just use its value inside the .done() handler.
This is asynchronous programming and works differently than synchronous, sequential programming. You must use asynchronous programming techniques with asynchronous ajax calls.
If you try to access parse inside the .done() handler and it's still empty in there, then the issue is likely that data.item isn't what you think it is and maybe isn't triggering the .each() loop and thus nothing is getting put into foo or parse. To debug this case, you should look at what exactly is in data and data.item.
This would be my suggestion:
$.ajax({
type: "GET",
url: "some/path/",
data: somedata
}).done(function( data ){
// no reason for these variables to be wider scope than here
var foo = [], parse;
$.each(data.item, function(i, value){
foo.push(value);
});
parse = foo.join(', ');
// look at parse here
console.log(parse);
// if parse still empty, then look at data and data.item here
// to see what they are for debug reasons
console.log(data);
console.log(data.item);
// now, you can use parse here
callSomeFunction(parse);
});

Using Javascript / JQuery to access an array built from an external XML file

I hope this is not too much of a newbe question but I've been pulling my hair out for a while now so thought I'd give in and ask for my first piece of advice on here.
I'm trying to read an external xml file using javascript / jQuery / ajax and place the retrieved data into an array so that I can then reference it later.
So far I seem to be doing everything right upto the point I put the data into the array but then I'm struggling to to read the data anywhere other than inside the function where I create it. Why am I not able to access the Array from anywhere other than in that function?
Here is my code...
Please help!!
$.ajax({
type: "GET",
url: "data.xml",
dataType: "xml",
success: do_xmlParser
});
function do_xmlParser(xml)
{
var myArray = new Array();
$(xml).find("tag").each(function ()
{
myArray.push($(this).find("innerTag").text());
});
console.log("inside "+myArray); // This outputs the array I am expecting
return myArray; // is this right???
}
console.log("outside: "+myArray); // This does NOT output the array but instead I get "myArray is not defined"
You're defining do_xmlParser as a callback to an asynchronous function (success of the jquery ajax call). Anything you want to happen after the ajax call succeeds has to occur within that callback function, or you have to chain functions from the success callback.
The way you have it now, the actual execution of code will go:
ajax -> file being requested -> console.log ->
file transfer done -> success handler
If you're doing some critical stuff and you want the call be to synchronous, you can supply the
async : false
setting to the ajax call. Then, you should be able to do something like this:
var myArray = [],
do_xmlParser = function (xml)
{
$(xml).find("tag").each(function ()
{
myArray.push($(this).find("innerTag").text());
});
};
$.ajax({
type: "GET",
url: "data.xml",
dataType: "xml",
success: do_xmlParser,
async: false
});
console.log("outside: " + myArray);
The async option doesn't work for cross-domain requests, though.
NOTE
I don't recommend doing this. AJAX calls are supposed to be asynchronous, and I always use the success callback to perform all of the processing on the returned data.
Edit:
Also, if you're into reading... I'd recommend jQuery Pocket Reference and JavaScript: The Definitive Guide (both by David Flanagan).
look close and you will see. You are actually firing up an array that dosen't exist. You have declared myArray inside function. Try do something like this.
console.lod("outside :"+do_xmlParser(xml)); // I think that when you merge a string and an array it will output only string, but I can be wrong.

Ajax HEAD request via Javascript/jQuery

I seem to be having some issues with making HEAD requests, and preserving the integrity of data in an array.
Given this snippet:
var imageTemp = Array();
$('*')
.each(function(index){
if($(this).css('background-image') != 'none'){
imageTemp.push($(this).css('background-image').slice(5, -2));
}
});
I capture the URLs of all background-images on a given page. Now, trying to grab the size of each image via HEAD requests for Content-Length, I use this snippet:
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
ajaxSizeRequest = $.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
success: function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
});
}
However, when I dump imageData via console.log, I each element (which should be an array containing the URL and the content-length) ends up as [undefined, XXXX] where XXXX is always the size of the last requested Content-Length
I'm stumped, though it appears to be a timing/scoping issue. Do I have a sort of race-condition occuring here?
The problem is that the single variables i and ajaxSizeRequest being captured by the callback function are the same variables for all instances of the callback function. I think if you call a function and pass the index variable to it and, at the same time, scope the request variable locally to the function itself use the response parameter of the done handler, you should end up with independent variables captured by the callback. It should then reference each array element and each response variable correctly.
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
updateImageData( i );
}
function updateImageData( i )
$.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
}).done(function(message,text,jqXHR){
imageData.push([imageTemp[i], jqXHR.getResponseHeader('Content-Length')]);
});
}
looks like your i isnt properly closed-in
in addition, you can't use ajaxSizeRequest because it too is pointing to just one request (probably the last, because the loop will execute very fast)
just wrap your success callback function as follows, changing the reference to ajaxSizeRequest:
success: (function(i){
return function(data,status,xhr){
imageData.push([imageTemp[i], xhr.getResponseHeader('Content-Length')]);
};
})(i)
You can scope I like so:
success: function(i){
return function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
}(i)
You have a single i variable which is shared by all of the callbacks.
Since AJAX is asynchronous, all of the callbacks run after your loop is finished, and they all get the same i.
To fix this, you need to move the AJAX call into a separate function that takes i as a parameter.
Thus, each callback will get a separate i parameter.
If anyone still having trouble with this, and since this post is, like, 5 years-old already, here's a more 'modern' version of the answer: just use let instead of var in the original post's for loop.
Info: Is there any reason to use the “var” keyword in ES6?
and: MDN - Let syntax

Categories

Resources