Jquery GET method inside a loop - javascript

I have an array of links with a url inside them, so I need to call 'get', wait for the response and extract what I want out of it and set an image's src to what I get back
I'm facing a problem where by the time the first 'get' is ready, the loop has finished, so basically every iteration of the loop gets the LAST 'data' response. Basically, only the last iteration of i gets a value, and even that's not always the right answer. It's just the last answer to come back
How do I go about fixing this issue?
for(i of instructors) {
jQuery( document ).ready($.get( i["image-link-post"], function( data ) {
i['image-link'] = data.guid.rendered;
}));
}

Since the loop is dealing with async calls, the iteration do not wait for ajax call to complete, and hence by the time the ajax call received a response, i is pointing to some other item of iteration. In this case, we need to maintain a local variable of iterating item and then pass the local reference to the ajax response handler. Checkout with below refactored code:
// Changed var image to let image
for (i of instructors) {
let image = i;
jQuery(document).ready($.get(image["image-link-post"], function (data) {
image['image-link'] = data.guid.rendered;
}));
}
// Below code also works
for (i of instructors) {
(function (image) {
jQuery(document).ready($.get(image["image-link-post"], function (data) {
image['image-link'] = data.guid.rendered;
}));
}(i));
}

Related

How pass data out of an AJAX function

I have a database with different link, I want to go fetch these link and put the inside an array.
I tried with the following code:
var amz=new Array();
function CreaArrayAmazon()
{$.ajax({
url: "php/amazon_affiliate.php",
success: function(data){
var leanamazon = JSON.parse(data);
for (i=0; i<leanamazon.length; i++)
{amz[i]=leanamazon[i].Link
}
}
})
}
I expect to find all the links in the "amz" array because it is a global variable, instead it saves links only when it is inside the AJAX function.
If I insert an "alert" inside the AJAX function (ex. alert(amz[i])) I can correctly see the data, instead if I insert an alert outside that I can't see anything, infact the amz array results to be empity.
Can someone tell me out to take that data out of there?
You might be misunderstanding what is going on here.
AJAX stands for Asynchronous Javascript and XML. Asynchronous means that your code doesn't always run in order.
In this case, your program functions like so../
function CreaArrayAmazon()
{
// Step 1: Make the Call
$.ajax({
url: "php/amazon_affiliate.php",
success: function(data){
// Step 3: When the call succeeds, execute the rest of this inner function.
var leanamazon = JSON.parse(data);
for (i=0; i<leanamazon.length; i++)
{amz[i]=leanamazon[i].Link
}
}
})
// Step 2: Continue Processing....
}
Step 2 happens far before Step 3. By the time your AJAX call finished, Javascript has already finished executing your CreaArrayAmazon call.
Instead, you need to have your inner function (Step 3) call an outside function to react to the new data you've received.

Controlling an $.ajax function within a js "for" loop?

Here's my issue. I have a js function that performs an $.ajax call to fetch some data from a server. When it gets that data back, I need to pass control back to the browser in order to show an update to a div.
The js function is itself within a for loop, and I need to ensure that the for loop does not advance until the js function has updated the div and allowed the Browser to display that update, at which point the for loop advances and the js function (with its ajax call) is called again, continuing until the for loop test causes the loop to end.
I've tried many different approaches - callbacks, promises etc, but to date I can't seem to get a handle on ensuring that the loop doesn't advance until the js function gets its server data, updates the div, causes the browser to display that update and fully completes.
Here's a simple stripped-down version of the function:
function myFunction (email) {
var request = $.ajax( {
url: 'getit.php',
cache: false,
async: false,
method: "post",
timeout: 1000,
data: "requesttype=getemailname&email="+encodeURIComponent(email)
});
request.done(function(response) {
$("#myDiv").html(response);
});
}
and here's part of the js that calls it:
.....
var emailscount = emails.length;
for(var i=0;i<emailscount;i++) {
myFunction (emails[i]);
}
.....
So, my issues are:
1) myFunction must allow the browser to display the updated div html - I'm not sure how to achieve that?
2) the for loop should only proceed when myFunction has received the data back from the server, updated the div html, AND allowed the browser to display that div.
At the moment, I have set the $.ajax call async flag set to "false" to stop execution until the data comes back, but how do I ensure the browser displays the new div content, and that the for loop does not proceed to call myFunction again until the previous myFunction call fully completes?
Any help you can give me would be very welcome, as right now I can't get this all to work!
Sounds like you need a recursive function, not a for loop with synchronous ajax calls
(function myFunction(i) {
$.ajax({
url: 'getit.php',
method: "post",
timeout: 1000,
data: {
requesttype : 'getemailname',
email : emails[i]
}
}).done(function(response) {
$("#myDiv").html(response);
if (emails[++i]) myFunction(i); // continue when this one is done
});
})(0);
Thanks for everyone's help! I'm making good progress (including taking care of JQuery deprecations!) but have run into a further problem. As I need to hand control back to the browser in order to show the refreshed div as I recurse, I'm calling a setTimeout as follows:
var nextBitOfWork = function () {
return myFunction(email);
};
setTimeout(nextBitOfWork, 0);
where myFunction (which recurses) now returns a promise when it's done doing it's $.ajax call.
If I simply call:
return myFunction(email);
without the setTimeout function construct above, the promise is passed through and all my promises are captured and allow me to get the array output I need and everything works great. But without the setTimeout I don't get the browser refresh. Using it as above I get the div update refresh displaying, but seem to lose the promise and so the script continues and I don't get to fill the array I use to capture values as I recurse.
Any thoughts on how to make sure the setTimeout passes on the promise?
Thanks

getJSON jQuery won't fill object

So I've got some code that retrieves a series of objects from an API. When I try to store them in a global variable, it doesn't seem to do anything. Here's the code:
var current_corpus = {};
function page_init() {
$.getJSON("http://resource1.com", function(data) {
populate_collections(data);
populate_citations(data);
});
}
function populate_collections(collections) {
$.each(collections, function (i, item) {
current_corpus[item] = [];
});
}
function populate_citations(collections) {
$.each(collections, function (index, collection) {
$.getJSON("http://resource2.com/" + collection.collection_id, function(data) {
current_corpus[collection] = data;
console.log(current_corpus);
});
});
}
When this finishes, current_corpus is completely empty. Logging these items verifies that they're being returned from the resources I'm posting to. I think there's just something about the asynchronous nature of these calls that I'm missing.
The line
current_corpus[item] = [];
is superfluous I think as the line
current_corpus[collection] = data;
should do the same thing while also tying data to the key object. Either way at the end of these functions running trying to access current_corpus via the console just gives me back an empty object.
Resources for dealing with AJAX stuff like this would be appreciated as well.
It all depends on what you want to do when the ajax requests complete. The A in ajax stands for Asynchronous meaning that such requests are non-blocking -- i.e. they will run in the background as control moves to the next line. Which explains why you're seeing an empty object right after the functions that invoke the ajax requests.
You can confirm that your code is working fine or you can do something once all the requests complete by using the following code snippet:
$(function() {
$(document).on('ajaxStop', function() {
console.log( current_corpus );
//do something with the now fully constructed object
});
});

Javascript global variable not modified in a callback

I'm trying to loop through every 1000 elements in a S3 bucket. This is because 1000 elements in the maximum returned by a get request. If there are more than 1000 elements, it get paginated, and the get request returns with a field call IsTruncated as true, and a marker (NextMarker) element to pass to the next call, letting the next get request start at the next 1000 elements.
I'm getting the data from the get request as a parameter in a callback function, and attempting to store the two pieces of above information in global variables for use in an outer loop. However, the outer loop goes off to infinity because the global variables are never modified in my get request callback function. I've tried using window.variable inside the callback to no avail. Could anyone help me restructure this code to accomplish my goals?
Thanks
Outter loop is commented out for debugging purposes. There are a number of debugging console.log statement I used to determined the root of the problem.
<script type="text/javascript">
s3_bucket = "link_to_s3_bucket";
var go = true;
var marker = "";
//while(go){
console.log('pass');
console.log(s3_bucket + marker);
$.get(
s3_bucket+marker,
"{}",
function(data) {
$(data).find('Key').each(function(i, key) {
key = key.innerHTML;
$("<a />", {
href : s3_bucket+key,
text : key
}).prependTo("#links");
$("<br />").prependTo("#links");
});
window.go = $(data).find('IsTruncated')[0].innerHTML;
window.marker = "&marker=" + $(data).find('NextMarker')[0].innerHTML;
},
"xml"
);
//}
console.log(go);
console.log(marker);
</script>
Your data returns asynchronously from Amazon, so those variables haven't been defined yet when you call those console logs. Put the console logs inside of the callback after the variable assignments.

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