Ajax saving array into global variables not working keep getting undefined - javascript

Trying to save an array retrieved from ajax into a global variable such that I may use it later on but keep getting undefined error
<script>
var items = [];
function add(value){
items.push(value);
}
$(document).ready( function() {
$.ajax({
type: 'POST',
url: 'xxxx.php',
dataType: 'json',
cache: false,
success: function(result) {
for(i=0; i < result.length; i++){
add(result[i]);
}
},
});
});
document.write(items[1])
</script>

This is an asynchronous AJAX call. The call to add will be done at a later time than the execution of document.write(items[1]);
So this is the right way to do it:
<script>
var items = [];
function add(value){
items.push(value);
}
$(document).ready( function() {
$.ajax({
type: 'POST',
url: 'xxxx.php',
dataType: 'json',
cache: false,
success: function(result) {
for(i=0; i < result.length; i++){
add(result[i]);
}
document.write(items[1])
},
});
});
</script>
This way the function that uses the result, will be executed when the result function is executed.
Think it this way: you said: Here is this lemon basket. Then you asked someone to go somewhere and get the lemons and before he returned you tried to count the lemons. Got it ?

You can use ajaxstop to call the method after the ajax request has completed. Place the following function in document ready:
$(document).ajaxStop(function () {
document.write(items[1]);
});
The above solution works but this is another option I used when waiting for multiple ajax functions to complete. This will call every time you complete an ajax request but there is a way to limit to one call if need be.

Related

Unable to update parent functions variable from inside $.ajax call

I am trying to push a value that is being returned inside the ajax call to an array outside of the call, but still inside the parent function. It seems that I am not able to access any variable and update it from inside the ajax success statement. Thanks in advance for the help.
var bill = [];
var billDate = [];
$(document).ready(function(){
$.ajax({
url: '../Js/readData.php',
data: "",
dataType: 'json',
success: function(data)
{
//var obj=JSON.parse(data);
var obj=data;
for (var x in obj)
{
bill.push(obj[x].Amount);
billDate.push(obj[x].Dates);
}
}
});
The ajax call is asynchronous so the variables are not updated immediately for availability outside of the success function. It is called after the time involved with loading the data from the server.
You may want to move the anonymous success function to an external function and do whatever handling you need in there.
$(document).ready(function(){
$.ajax({
url: '../Js/readData.php',
data: "",
dataType: 'json',
success: mySuccessFunction
});
var mySuccessFunction = function(obj) {
for (var x in obj)
{
bill.push(obj[x].Amount);
billDate.push(obj[x].Dates);
}
}

Javascript JQuery On Select Change Get Result and pass to outside

I have the following code which works on the event that a select box is changed.
When it changes, the ajax call will pass the results to the variable result.
My problem is that I cannot get that data outside this function.
The code:
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl'+this.value,
method: 'GET',
success: function(result) {
console.log(result); //Just checking it's there
external = result;
}
});
});
console.log(external); //Returning Undefined
I need external to be available here outside the function above.
How do I do this?
You can create the variable outside of the event and than access it outside. But as ajax is ascychron, the variable would still be undefined:
var external;
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl' + this.value,
method: 'GET',
success: function(result) {
external = result;
}
});
});
// this would be still undefined
console.log(external);
You can write the console.log inside your success, or create your own callback function. Then you can log or handle the data otherwise after the ajax request.
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl' + this.value,
method: 'GET',
success: function(result) {
myCallback(result);
}
});
});
function myCallback(external) {
console.log(external);
}
Even shorter would it be possible in this example, if you directly use your callback function as success callback without wrapper. And because GET is the default request type, we could remove it too:
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl' + this.value,
success: myCallback
});
});
function myCallback(external) {
console.log(external);
}
I'm sorry if I'm misunderstanding the question:
What it sounds like is that you are trying to get the data from external but the ajax call hasn't called the callback yet, so the data hasn't been set.
If I can recommend how to fix it, call the code that references external from the callback itself so you can guarantee that you have the data when you need it.
You are not able to access variable because it comes in picture after ajax completion and you are trying to access it directly, since you don't have any idea how exact time this ajax takes each time so you need to define a function like this
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl'+this.value,
method: 'GET',
success: function(result) {
console.log(result); //Just checking it's there
saySomething(result); //result will be injected in this function after ajax completion
});
});
function saySomething(msg) {
console.log(msg); //use variable like this
}
I hope my code is help to you.
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl'+this.value,
method: 'GET',
async: false, // stop execution until response not come.
success: function(result) {
console.log(result); //Just checking it's there
external = result;
}
});
});
console.log(external); //now it should return value
Define the variable external above your first function like so:
var external;
$('#myselect').on('change', function() {
$.ajax({
url: 'myurl'+this.value,
method: 'GET',
success: function(result) {
console.log(result); //Just checking it's there
external = result;
}
});
});
console.log(external);

Jquery Ajax Call Return

I have made a function which is the one below that i pass data to and returns the result as is. I made this way because i will be needing a lot of ajax call and i just made a function that i pass the data to and get the result as is and work with the result.
function FunctionsCall(data){
var ret;
$.ajax({
type:'GET',
url: 'includes/helpers/functions.php',
dataType:"json",
data: data,
success: function(result){
ret = result;
}});
return ret;}
Now i am calling it where i need it:
$('#register-name, #register-surname').keyup(function(e) {
var x = FunctionsCall({query: $(this).val(), funcid: 1});
(x!==1) ? $(this).addClass('input-has-error') : $(this).removeClass('input-has-error'); });
But strange is that i always see x as undefined. Pointing out the ret is filled with either 1 or 0 i don't know why it is not being passed to x.
Can you please help me out? It might be simple but i just experiment when needed with javascript and jquery.
Regards
ret doesn't get set until the success function runs, which is when the ajax finishes. FunctionCall returns straight away however. You'll either need to return the ajax deferred object or put your addClass/removeClass functionality in your success function.
A way to add your addClass/removeClass functionality to your success function would be like this:
function FunctionsCall(data, successFn) {
$.ajax({
type: 'GET',
url: 'includes/helpers/functions.php',
dataType: "json",
data: data,
success: successFn
});
}
$('#register-name, #register-surname').keyup(function(e) {
var element = $(this);
var data = { query: element.val(), funcid: 1 };
var successFn = function(x) {
if (x !== 1) {
element.addClass('input-has-error')
} else {
element.removeClass('input-has-error');
}
}
FunctionsCall(data, successFn);
});
The problem is that the ajax call takes time to execute, whereas your processing of x is immediately after the call to FunctionsCall
Imagine that in order to go to the php file and get the result, the browser has to send a request over the wire, the server needs to process the request and return the value, again over the wire. This process takes an unpredictable amount of time as it relies on network connections and server specs / current load.
The code to call the function and process the result happens immediately after this step and as such won't have the required values when it is run (browsers are much quicker at executing the next step than networks are at processing requests).
The best thing to do is to wrap your processing code up in it's own function, so it isn't immediately called, then call that function with the result once you get it. Like this:
// function defined, won't be called until you say so
var processMe = function(result) {
alert(result);
}
$.ajax({
// ajax params
success: function(result) {
// function called within success - when we know the request is fully
// processed, however long it takes
processMe(result));
}
});
You could also do the processing directly in the success block but the advantage of using a function is it's there to re-use in the future, plus, you also get to give it a nice understandable name, like outputValidatedMessage.
you must send ajax request syncronous
function FunctionsCall(data){
var ret;
$.ajax({
type:'GET',
async: false,
url: 'includes/helpers/functions.php',
dataType:"json",
data: data,
success: function(result){
ret = result;
}
});
return ret;
}
Ajax calls are asynchronous.
This means that while you call $.ajax(), the function continues to run and return x which is undefined, as the ajax response has not been send yet.
function FunctionsCall(data){
var ret;
$.ajax({
type:'GET',
async: false,
url: 'includes/helpers/functions.php',
dataType:"json",
data: data,
success: function(result){
ret = result;
}
});
return ret;
}
The below should work for you
function FunctionsCall(data){
var ret;
$.ajax({
type:'GET',
url: 'includes/helpers/functions.php',
dataType:"json",
data: data,
success: function(result){
(result !==1 ) ? $(this).addClass('input-has-error') : $(this).removeClass('input-has-error'); });
}});
}
maybe is because the ajax function is called asynchronously so the line var x= .... doesn't wait for the asignment and thats why is undefined. for that you should use a promise here is an example http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/
http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html
check if the following works, may be your GET method is taking time to execute.
var x;
function FunctionsCall(data){
var ret;
$.ajax({
type:'GET',
url: 'includes/helpers/functions.php',
dataType:"json",
data: data,
success: function(result){
ret = result;
x= result;
alert(x)
}});
return ret;}
if the snippet works, you should make you synchronous async: false or make callback function
try this code.
function FunctionsCall(data,callback) {
try {
ajax({
type: 'GET',
url: 'includes/helpers/functions.php',
dataType: "json",
data: data,
success: function (result) {
callback(result);
}
});
} catch(e) {
alert(e.description);
}
}
$('#register-name, #register-surname').keyup(function (e) {
var data = {
uery: $(this).val(),
funcid: 1
};
FunctionsCall(JSON.stringify(data), function (result) {
(result !== 1) ? $(this).addClass('input-has-error') : $(this).removeClass('input-has-error');
});
});

Use of async on successive AJAX calls

Question here about use of successive AJAX calls and async. Its a bit messed here because of how the data is set up. I need to return listings, but the sever only returns 10 per query, and the only way to determine the total number of listings is a separate query with the boolean returnTotal as true instead of false. This returns the number of listings only, and not the listing results themselves. However, if I run the calls synchronously, the variable startItem (which increments on each loop to load data starting at the next block of listings) doesn't seem to populate before the next call finishes, and results get duplicated. Any way to avoid running both as async? Apologies if my code is batshit ridiculous, as I'm relatively new to jquery.
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
async: false,
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
},
});
for (i = 0; i < totalPages; i++){
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem = startItem + 10;
popResults();
},
});
}
The problem here is that you do not increment startItem until you receive a response. Your code is probably making multiple requests with startItem === 1 before the first response is even received, and so you will get some really weird behavior (probably will get duplicate responses, and you will only get the first few pages of data).
Avoid using synchronous calls because they will tie up other resources (like javascript).
In this case if you want to insure that you get the data in order, you can make it a serial chain of AJAX calls.
To get serial behavior and enjoy the benefits of AJAX, instead of using a loop make your callback function do the next AJAX request after incrementing startItem.
This is easier if you organize your code into functions. To wit:
function GetData()
{
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: GetData_Callback
});
}
function GetData_Callback(data)
{
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem += 10; // increment startItem
popResults();
if (startItem / 10 < totalPages)
{
GetData(); // get next "page" of data
}
}
var startItem = 1; // global variable will be mutated by GetData_Callback
GetData(); // get first "page" of data
To do this in parallel typically requires management of the parallel responses (you can use semaphores, etc.). For example (psuedo code) you could do something like this:
var pages = [];
var totalPages = GetTotalPages(); // request via ajax like you mentioned (function not shown)
var pagesLoaded = 0;
for(var i = 0; i < totalPages; i++)
{
GetData(pageIdx);
}
function GetData(pageIdx)
{
$.ajax({ ..., success: function(data){GetData_Callback(pageIdx,data);}});
}
function GetData_Callback(pageIdx, data)
{
pages[pageIdx] = data; // assign this specific page of data
pagesLoaded++;
if (pagesLoaded === totalPages)
{
// fully loaded; trigger event or call function to render, etc.
}
}
Do you just mean without the async: false?
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
success: function(data) {
console.log('test1'); // first response ok
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
var startItem=0;
console.log(totalPages); // total page should be equal too "loop" logged
for (i = 0; i < totalPages; i++){
console.log('loop'); // enter the loop
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
console.log('test2'); // number of test 2 = nb of loop = totalPages
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem = startItem + 10;
popResults();
},
});
}
},
});
The problem here is that you do not increment startItem until you receive a response. Your code is probably making multiple requests with startItem === 1 before the first response is even received, and so you will get some really weird behavior (probably will get duplicate responses, and you will only get the first few pages of data).
Try this instead. It still uses your loop but it increments startItem in the loop before the next request is made to insure that all pages of data are requested.
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
async: false,
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
},
});
var startItem = 1;
for (i = 0; i < totalPages; i++){
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
popResults();
},
});
// increment start item BEFORE the next request, not in the response
startItem += 10; // now the next request will be for 11, 21, 31, 41, etc...
}
You may want to get familiar with your javascript debugger to see the behavior for yourself.

Ajax call with nested ajax calls in for each

I'm experiencing the following problem.
I have the following nested / foreach loops ajax call structure:
var children = [];
$.fn.ajaxHelper.loadAjax({
url: someUrlReturningJsonOfChildren,
cache: true,
callback: function(options) {
var json = options.json;
$.each(json, function (i) {
// get the details of this child
$.fn.ajaxHelper.loadAjax({
url: urlForDetailsUsingId,
cache: true,
callback: function(options) {
var json = options.json;
children[i] = json;
}
});
}
}
});
// want to do something with (newly filled) children here
As you can imagine, I'm running into the trouble that the ajax calls are asynchronous (duh), but I want to do something with the children array only when all the ajax calls are done. Otherwise I'm obviously dealing with an incomplete array.
I have been looking at some jQuery solutions such as Deferred objects (using $.when().then() and such), but that would only solve the problem if I would not have the foreach-loop (as far as I can tell).
Also, changing the REST API (where the ajax calls are going) is not an option unfortunately, due to specified requirements regarding the API.
Ok, so without further ado: can anyone of you geniuses help me with this? :-)
ajax is asynchronous by default but you can turn it off. Here goes the API on how to do it
https://api.jquery.com/jQuery.ajax/
heres a little demp
$.ajax({
url: my_url.php,
type: "POST",
async: false,
dataType: 'json'
});
Or just make your next ajax call in a success function (Recommended)
function testAjax(handleData) {
$.ajax({
url:"getvalue.php",
success:function(data) {
//next ajax call here
}
});
}
You must run ajax query when previous query is completed with success (in jQuery onSuccess callback)
I had a smiler issue... below is a simplified version of my solution.
Step one: Declare global variables.
var results1,
results2,
[resultsN];
Step two: Make a function that accepts the results of each AJAX call as parameters.
function foo(results1, results2, [resultsN]) {
if (results1, results2, [resultsN]) {
//... do whatever you want with all of your results
}
}
Step three: Call all of the AJAX functions, set results to global variables, and call function foo for each.
function ajax() {
//AJAX call 1
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results1 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
//AJAX call 2
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results2 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
};
This method has the advantage of running as fast as the longest AJAX call takes. If you simply nest AJAX queries in the complete event then you will have to wait for each AJAX call to complete before moving to the next one...

Categories

Resources