making multiple ajax calls within a for loop - javascript

I'm a relative newbie to javascript and I'm trying to make multiple ajax calls within a for loop. It loops through the elements of an array using a different url for an ajax call each time it goes through the loop. The problem is that the value of the variable 'test' is always equal to "condition4". I'm used to other languages where the value of 'test' would be "condition1", then "condition2" etc as it goes through the for loop. Here is a simplified version of my code:
var myData = [];
var cnt = 0;
var link;
var myCounter = 0;
var myArray = ["condition1", "condition2", "condition3", "condition4"];
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[myCounter];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
}
function GetJSON(callback) {
$.ajax({
url: link,
type: 'GET',
dataType: 'json',
success: function (results) {
callback(results);
}
});
}

I think you can solve this issue by sending and receiving myCounter value to server
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
$.ajax({
url: link,
type: 'GET',
dataType: 'json',
data: { myCounter: myCounter}
success: function(results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = results.data[i].myCounter
myData[cnt] = {
"id": id,
"test": test
};
cnt++;
}
}
});
}

When you are executing the loop, it attaches the myCounter reference. Then, due to the async task, when it finishes and call 'myCounter', it has already achieved the number 4. So, when it call 'myCounter', it is 4. To isolate the scope, you need to create a new scope every iteration and isolating each value of 'myCounter'
for (x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
//IIFE
(function() {
var ownCounter = myCounter; //Isolating counter
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[ownCounter];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
})();
}
Or...
for (let x = 0; x < myArray.length; x++) {
link = "https://test.com/" + myArray[x];
myCounter = x;
GetJSON(function (results) {
for (i = 0; i < results.data.length; i++) {
var id = results.data[i].identifier;
var test = myArray[x];
myData[cnt] = { "id": id, "test": test };
cnt++;
}
});
}

Related

jQuery deferred queue in for loop

I have the following function:
function getData(a,url) {
var deferreds = [];
var i = 1;
for (i = 1; i <= a.length; i++) {
var count = i;
var back = a[i]['link'];
var path = "http://example.com";
deferreds.push(
$.ajax({
url:path,
data:{back:back,link:url},
type:"POST",
async: true,
delay: count
}).done(function(data) {
//success function here
}));
}
return deferreds;
}
My question is how to make this script to run a queue, for example I have 2000 requests, how to put them in a queue of 100 one by one?
Maybe in this way (Of course is a simplification)
var completed = 0;
var limit_simultaneous = 100;
var total_requests = 2134 // Assign your var
function send_block() {
for (i = 0; i < limit_simultaneous; i++) {
$.ajax({
url:path,
data:{back:back,link:url},
type:"POST",
async: true,
}).done(function(data) {
completed++;
send_next_block();
//success function here
}));
}
}
function send_next_block()
{
if (completed == limit_simultaneous && total_requests > 0) {
total_requests = total_requests - completed;
if (total_requests < limit_simultaneous) {
limit_simultaneous = total_requests;
}
completed = 0;
// Fire again
send_block(); // Send another 100
}
}
I hope it helps.
EDIT Edit to take account about the total requests. Maybe is not a working code, but it is the idea.

Passing JSON parse value to a global variable

$(function() {
var global_datalength = 0;
leavereminder();
alert(global_datalength);
});
function leavereminder() {
$.getJSON("<?=base_url()?>home/leavereminder",
{},
function(data) {
if(data.length != 0) {
for(x=0; x<data.length; x++) {
var lblm = document.createElement('div');
lblm.innerHTML = '<label>'+data[x]+'</label>';
lblm.className = 'alert alert-info';
document.getElementById('notifbody').appendChild(lblm);
}
}
var datalength = data.length;
});
global_datalength = datalength;
}
I have a global variable of global_datalength and i want to replace it with my return json
but when i alert my code it always 0. it didnt pass my global_datalength = datalength. because when outside of json function my data.length is unknown
Remove the var keyword on global_datalength to make it global.
You can also use window.global_datalength.
Another way is to declare the variable outside the jQuery ready function.
Your JSON call is async. That means the alert will be called before the JSON has returned from the server.
What you can do is:
function leavereminder() {
$.ajax({
dataType: "json",
url: "<?=base_url()?>home/leavereminder",
async: false,
success: function(data) {
if(data.length != 0) {
for(x=0; x<data.length; x++) {
var lblm = document.createElement('div');
lblm.innerHTML = '<label>'+data[x]+'</label>';
lblm.className = 'alert alert-info';
document.getElementById('notifbody').appendChild(lblm);
}
}
global_datalength = datalength;
},
});
}
Need to keep global_datalength outside the jQuery function.
Also since leavereminder is asynchronous, you might want to keep global_datalength = datalength; inside the function(data)
var global_datalength = 0;
$(function () {
leavereminder();
});
function leavereminder() {
$.getJSON("<?=base_url()?>home/leavereminder", {},
function (data) {
if (data.length != 0) {
for (x = 0; x < data.length; x++) {
var lblm = document.createElement('div');
lblm.innerHTML = '<label>' + data[x] + '</label>';
lblm.className = 'alert alert-info';
document.getElementById('notifbody').appendChild(lblm);
}
}
global_datalength = data.length;
alert(global_datalength);
});
}

Value won't push to array

In the code below, I assign a value to a variable from JSON with this var tag = data[j]['text']; and I output it with this console.log(tag); (for testing) which works.
I try to push the values into an array with tags.push(tag); but it WILL NOT WORK!
Why won't these values go into the array? I am just trying to get the contents of tag into an array...
function GetAvailableTags() {
var url = '/TextCodes/TextCodes?key=';
var tagGroups = [];
$('.ui-autocomplete-input').each(function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.getJSON(url + key, function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
});
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
});
}
Thanks for your help.
Because $.getJSON is an asynchronous function. It means that your code
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
will be executed before the $.getJSON callback function :
function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.getJSON(url + key, function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
}
It is why your variable seems to be empty when look into in your code above, but how it is possible that the data are printed with console.log(tag); in the callback function.
Update
Here is an example of using $.ajax method instead of $.getJSON to specify that the data must be retrieved synchronously using the parameter asynch : false
By that way, the server call response (success callback) is mandatory to continue the process. The disadvantage of this non-standard way is that your web page could be freezed waiting the server response. It is not the best elegant way to do that, but sometimes it is useful.
function GetAvailableTags() {
var url = '/TextCodes/TextCodes?key=';
var tagGroups = [];
$('.ui-autocomplete-input').each(function () {
var key = $(this).attr('id');
var tags = [];
//console.log(key);
$.ajax({
url: url + key,
type: 'POST',
asynch: false,//specify to stop JS execution waiting the server response
success: function (data) {
for (var j = 0, len = data.length; j < len; j++) {
var tag = data[j]['text'];
console.log(tag);
tags.push(tag);
}
},
error : function(jqXHR, textStatus, errorThrown) {
alert('an error occurred!');
}
});
console.log(tags.length);
for (var k = 0, len = tags.length; k < len; k++) {
console.log(tags[k]);
}
});
}
My solution is kind of long and stupid, but it works. Now, I can access the variables like an array textCodes['taxes']. sdespont's async note helped, too.
var textCodes = GenerateTextCodes();
console.log(textCodes);
function GenerateTextCodes() {
var arr = [];
$('.ui-autocomplete-input').each(function () {
var id = $(this).attr('id');
arr[id] = GetAvailableTags(id);
});
//console.log(arr['taxes']);
return arr;
}
// get all autocomplete element IDs and put them into an array
function GetAvailableTags(key) {
var url = '/TextCodes/TextCodes?key=';
var tags = [];
$.ajax({
url: url + key,
type: 'GET',
async: false,
success: function (data) {
//console.log(data[0].text);
//console.log(data.length);
for (var i = 0; i < data.length; i++) {
//console.log(data[i].text);
tags.push(data[i].text);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('an error occurred!');
}
});
//console.log(tags);
return tags;
}

returning a value after for loops

So, I have been trying for the past few hours to get an result out of a function after performing some for loops :
Cluster.prototype.initiate_api_data_fetching = function(username) {
var self = this,
object = [];
return self.initiate_available_market_search(username, function(data_object){
var json_obj = JSON.parse(data_object);
for(var obj_key in json_obj) {
for (var i = json_obj[obj_key].length - 1; i >= 0; i--) {
self.initiate_market_items_data_fetching(username, json_obj[obj_key][i].site, function(data_obj){
var json_object = JSON.parse(data_obj);
for(var data_key in json_object) {
for (var j = json_object[data_key].length - 1; j >= 0; j--) {
object.push(json_object[data_key][j]);
/*log(object);*/
};
};
log(object);
});
};
};
});
};
Making abstraction of all the variables and other things that make no sense to you readers, I would just like to know how can I return the object array with the data that I\m pushing in it. Everything is fine if I\m logging where the /*log(object);*/ is, but if I want to see what the object contains at the end of the function, I get an empty array.
I suggest you add a callback to your main function and call it when done..
Cluster.prototype.initiate_api_data_fetching = function (username, callback) {
var self = this,
object = [];
return self.initiate_available_market_search(username, function (data_object) {
var json_obj = JSON.parse(data_object)
, counter = 0;
function done() {
counter -= 1;
if (counter === 0) {
callback(object);
}
}
for (var obj_key in json_obj) {
if (!json_obj.hasOwnProperty(obj_key)) { continue; }
for (var i = json_obj[obj_key].length - 1; i >= 0; i--) {
counter += 1;
self.initiate_market_items_data_fetching(username, json_obj[obj_key][i].site, function (data_obj) {
var json_object = JSON.parse(data_obj);
for (var data_key in json_object) {
if (!json_object.hasOwnProperty(data_key)) { continue; }
for (var j = json_object[data_key].length - 1; j >= 0; j--) {
object.push(json_object[data_key][j]);
/*log(object);*/
}
}
done();
});
}
}
});
};
PS. 1 assumption is that initiate_api_data_fetching is async.
PS. 2 Follow the advice from the commenters above to improve your code. I answered your immediate question by showing you how to synchronise async calls, but don't stop there.

Refactor two jQuery UI auto-completes to be more Functional & DRY

I have two jQuery UI auto-completes on the same page and I'd like to make the code more "functional" and terse. My background is almost strictly OO and I'd like to get more serious about writing more functional JavaScript.
Both of these functions are properties of an object literal that I'm using to namespace the functions on the page. Right now there is a lot of code that's repeated between the functions and I'd like to use something similar to the "partial application" pattern to reduce the code.
autocomplete 1:
initProject : function(){
var selected = 0;
var suggestions = [];
var projs;
var len;
$("#projectNum").autocomplete({
source : function(req, add){
$.getJSON("projectList.do?method=viewProjectListJSON&contractID=" + req.term, function(data){
//clear the suggestions array
suggestions = [];
projs = data[0];
len = projs.length;
for(var i = 0; i < len; i++){
suggestions.push(projs[i][1]);
};
add(suggestions);
});//end getjson callback
},
minLength : 2,
select : function(){
thisval = $(this).val();
for(var i = 0;i < len; i++){
if(thisval === projs[i][1]){
$("#projectID").val(projs[i][0]);
return;
}
}
}
})
},
autocomplete 2:
initCAU : function(){
var selected = 0;
var suggestions = [];
var caus;
var len;
$("#cauNum").autocomplete({
source : function(req, add){
$.getJSON("cauList.do?method=viewCAUListJSON&cauNumber=" + req.term, function(data){
suggestions = [];
caus = data[0];
len = caus.length;
for(var i = 0; i < len; i++){
suggestions.push(caus[i][1].toString());
};
add(suggestions);
}); //end getjson callback
},
minLength : 2,
select : function(){
thisval = $(this).val();
for(var i = 0;i < len; i++){
if(parseInt(thisval,10) === caus[i][1]){
$("#cauID").val(caus[i][0]);
return;
}
}
}
})
},
//factored-out common code...
var autocompleter = function(urlPrefix, fragment) {
var selected = 0;
var suggestions = [];
var items;
var len;
return ({
minLength: 2,
source: function(req, add) {
$.getJSON(urlPrefix + req.term, function(data) {
suggestions = [];
items = data[0];
len = items.length;
for(var i = 0; i < len; i++) {
suggestions.push(projs[i][1]);
};
add(suggestions);
}); //end JSON callback
}, //end source callback
select: function() {
var thisVal = $(this).val();
for(var i = 0; i < len; i++) {
if(thisVal === items[i][1]) {
$(fragment).val(items[i][0]);
return;
}
}
} //end select callback
});
};
//verbose but clear way to achieve what you were doing before.
var initCAU = function() {
var attachTo = "#cauNum";
var urlPrefix = "cauList.do?method=viewCAUListJSON&cauNumber=";
var fragment = "#cauID";
$(attachTo).autocomplete(autocompleter(urlPrefix, fragment));
};
var initProject = function() {
var attachTo = "#projectNum";
var urlPrefix = "projectList.do?method=viewProjectListJSON&contractID=";
var fragment = "#projectID";
$(attachTo).autocomplete(autocompleter(urlPrefix, fragment));
};

Categories

Resources