Sequential and Dynamic Number of Ajax Calls in For Loop - javascript

var data = [{start_date:20180601,end_date:20180701},{start_date:20180801,end_date:20180901},{start_date:20181001,end_date:20181101},{start_date:20181201,end_date:20190101}];
var requests = [];
for (var i = 0; i < data.length; i++) {
(function(i, data) {
requests.push(function() {
jQuery.ajax({
url: 'https://reqres.in/api/users?page=1',
method: 'GET',
success: function(result) {
console.log(i); // 0
requests[i].apply(undefined, []);
}
});
});
console.log(i); //counts up
})(i, data);
};
requests[0].apply(undefined,[]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am wondering, how come with this code:
for (var i = 0; i < data.length; i++) {
(function(i, data) {
requests.push(function() {
jQuery.ajax({
url: wpApiSettings.root + 'superdooperendpoint/' + apikey + "/" + data[i].start_date + "/" + data[i].end_date,
method: 'GET',
beforeSend: function(xhr) {
// Set nonce here
xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);
},
success: function(result) {
success_callback({
start_date: data[i].start_date,
end_date: data[i].end_date,
span: data[i].span,
result: result
});
console.log(i); // 0
requests[i].apply(undefined, []);
}
});
});
console.log(i); //counts up
})(i, data);
};
When I do the first console.log() in the success function it is always 0, not undefined, yet while outside of the success function it counts up in the iterating for loop. How can I get it to count up in the success function as well?

The following paints the updated value of i
Parallel Calls
var data = [{start_date:20180601,end_date:20180701},{start_date:20180801,end_date:20180901},{start_date:20181001,end_date:20181101},{start_date:20181201,end_date:20190101}];
var requests = [];
for (var i = 0; i < data.length; i++) {
(function(i, data) {
requests.push(function() {
jQuery.ajax({
url: 'https://reqres.in/api/users?page=1',
method: 'GET',
success: function(result) {
console.log(i);
}
});
});
})(i, data);
};
for (var i = 0; i < requests.length; i++) {
requests[i].apply(undefined, []);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Sequential Calls
var data = [{start_date:20180601,end_date:20180701},{start_date:20180801,end_date:20180901},{start_date:20181001,end_date:20181101},{start_date:20181201,end_date:20190101}];
var requests = [];
for (var i = 0; i < data.length; i++) {
(function(i, data) {
requests.push(function() {
jQuery.ajax({
url: 'https://reqres.in/api/users?page=1',
method: 'GET',
success: function(result) {
console.log(i);
i++;
if(i < requests.length) {
requests[i].apply(undefined, []);
}
}
});
});
})(i, data);
};
requests[0].apply(undefined, []);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Explanation - When you iterated over the function, for each function in requests array a value of i was passed/stored just like an argument. When you invoke the requests[0] from outside, on completion of the function, the stored value of i i.e. 0 is painted. And then, you again trigger the function stored at index = 0 i.e. you end up creating an infinite loop. In order to paint the appropriate value, loop over the requestsarray and call the individual function one by one to see the appropriate value of i being logged.

You need to assign i to a different local variable of the nested function and put the definition of i out of the block;
let i = 0;
for (; i < 100; i++) {
((n) => new Promise(
(res, rej) => setTimeout(res, 100)
).then(() => console.log(i,n))
)(i);
}

Related

get variable value in callback function

I have one callback function
function QueryKeyword(keyword, site, callback) {
var querykeyword = keyword;
var website = site;
$.ajax({
url: "http://www.test.com",
jsonp: "jsonp",
dataType: "jsonp",
data: {
Query: querykeyword
},
success: callback
});
}
I am calling this function with in for loop like this :
for (i = 0; i < questionTerm.length; i++) {
for (j = 0; j < site.length; j++) {
var searchTerm = questionTerm[i] + ' ' + $('#search').val();
QueryKeyword(searchTerm, site[j], function(reslt) {
// I need to get j variable value here
console.log(j);
});
}
}
Now I need to get "j" variable value in function see I console the j variable value but it does not get the j variable value.
Would you please let me know how I can fetch the value in this.
Thanks in advance
The problem is, that at the moment of your callback, j was reassigned multiple times to something different.
There are a few options you could do.
call your callback with the params you need
function QueryKeyword(keyword, site, index, callback) {
// ...
$.ajax(
success: function(result) {
// call the callback with a second param (the index j)
callback(result, index);
}
)
}
QueryKeyword(searchTerm, site[j], j, function(reslt, param) {
// param is j
console.log(result, param);
});
save the var in a closure
(function() {
var value = j;
...
})();
use forEach
questionTerm.forEach((term, i) => {
site.forEach((s, j) => {
// we are in a closure,
// j will be correct here.
QueryKeyword(term, s, function(reslt) {
// j is still correct here
console.log(j);
});
})
});
if you use es6, you could use let keyword. Here is some good explanation, how it works when using for loops
for(let i = 0; i < 10; i++) {
console.log(i);
setTimeout(function() {
console.log('The number is ' + i);
},1000);
}
You have to pass it in separately:
definition
function QueryKeyword(keyword, site, index, callback)
{
...
}
execution
QueryKeyword(searchTerm, site[j], j, function(reslt) {
// I need to get j variable value here
console.log(j);
});

making multiple ajax calls within a for loop

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++;
}
});
}

Refresh & Clear JQuery Chosen plugin dynamically in ajax request

I am trying to dynamically populate the jquery chosen plugin both with "optgroup" and "option". I therefore have nested ajax requests and forloops:
$.ajax({
url: '#Html.Raw(Url.Action("GetCat", "MController"))',
data: { ID: metada },
success: function (data) {
var categories = data.split(",");
for (i = 0; i < categories.length; i++) {
$.ajax({
url: '#Html.Raw(Url.Action("GetCat", "MController"))',
data: { ID: cetada },
success: function (data) {
$("#picker").append("<optgroup label='" + categories[i] + "'>");
var subcategories = data.split(",");
for (i = 0; i < subcategories.length; i++) {
$("#picker").append("<option value='"+subcategories[i]+"'>" + subcategories[i] + "</option>")
}
$("#picker").append("</optgroup>");
}
});
}
$("#picker").trigger('chosen:updated');
}
});
Currently when I run the above the chosen select is empty and no options or optgroups are visible.
I think you need to use promises for this:
var promises = [];
for (var i = 0; i < categories.length; i++) {
promises.push(
(function(innerI){
return $.ajax({
url: '#Html.Raw(Url.Action("GetCat", "MController"))',
data: { ID: cetada },
success: function (data) {
var optgroup = $('<optgroup>').attr('label', categories[innerI]);
var subcategories = data.split(",");
for (var i = 0; i < subcategories.length; i++) {
var option = $('<option>').val(subcategories[i]).text(subcategories[i]);
optgroup.append(option);
}
$("#picker").append(optgroup);
}
});
})(i)); // unbind i to make closure work.
}
$.when.apply($, promises).then(function() {
$("#picker").trigger('chosen:updated');
});
UPDATE1:
I missed closures on first look, now th code is updated.
UPDATE2:
Rewrote working with tags inside success callback of ajax request.
UPDATE3:
Here is simple demo, I've commented some non-important code to show how it works.

Adding loop to ajax parameters

I'm looking to dynamically add properties and values to my ajax parameters, does anybody know how to do this? I can't seem to figure out how to accomplish this task. Thanks
doLookup = function($field, url, query, process, filterIdArray) {
$field.addClass("ajax-wait");
return ajax(url, {
parameters: {
"t:input": query,
"t:inputFilter": $filterField.val(),
for (var i = 0; i < filterIdArray.length; i++) {
"t:inputFilter_" + i : $("#" + myStringArray[i]);
},
},
success: function(response) {
$field.removeClass("ajax-wait");
return process(response.json.matches);
}
});
};
Create parameters outside the ajax function like:
params = {};
params["t:input"] = query;
params["t:inputFilter"] = $filterField.val();
for (var i = 0; i < filterIdArray.length; i++) {
params["t:inputFilter_" + i] = $("#" + myStringArray[i]);
}
return ajax(url, {
parameters: params,
success: function(response) {
$field.removeClass("ajax-wait");
return process(response.json.matches);
}
});
};

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;
}

Categories

Resources