i ma trying to fetch list of names of htmls from ajax call and then for each html another ajax call and then i am trying to append it using handlebar. but this is not happening with below code. can somebody help me in debugging it :
$.getJSON('api/filterTemplate/' + pageName.page, function (data) {
var promises = [];
$.each(data, function (i, rec) {
promises.push($.get('commonCore/templates/' + rec.templateHtml));
});
$.when.apply(this, promises).then(function() { //after all requests complete
$.each(arguments, function(i, html) {
var filterTemplate = Handlebars.compile(html);
replaceFilterTemplate(filterTemplate,data[i].classids);// this functions appends html to div -data[i].classids
})
})
});
after each html is fetched it should be appended and then next call should happen
$.get returns the jqXHR Object. That's what you're actually adding to your promises array.
You should use synchrone calls, or reformat your code to handle all the fetches async and then proceed through the promises.
Synchrone alternative:
$.each(data, function (i, rec) {
$.ajax({
url: 'commonCore/templates/' + rec.templateHtml,
async: false,
success: function(result) {
promises.push(result);
}
});
});
Related
I am trying to learn more about ajax calls and doing some testing. I am running into a snag due to async.. With the help of this website I have found what I believe should work.. Somehow things still arent running properly. I have fiddled a ton, but still have yet to make things work how Id like.
Background:
Capturing a variable amount of ids in array
Iterating through $.ajax calls to update ids (api batch request not possible).
$(document).ready(function() {
$("#button").click(function() {
var deffered, deferreds = [];
$.each(arr, function(i, array) {
deferred = $.ajax({ ...
success: function(data) {console.log('complete');},
error: function(data) {...}
});
deferreds.push(deferred);
});
$.when.apply($, deferreds).done(console.log('done'));
});
});
When running code above (also see fiddle for more details) and checking my console.log it shows 'done' occurring before any 'completes' are made (picture below).
Please help me understand what is wrong with code. I want all ajax calls to console.log('complete') before the console.log('done'). From my understanding that is the point of $.when.apply.
I have added the sample working code. Please add promise in each request
deferred = $.ajax({ ...
success: function(data) {console.log('complete');},
error: function(data) {...}
}).promise();
and change in this line
$.when.apply(this, deferreds)
Please run this code and verify it
function doSomething() {
var arrDef = [];
for (var i = 0; i < 2; i++) {
var deferred = $.ajax({
url:"https://jsonplaceholder.typicode.com/todos/1",
type: "GET",
contentType: "application/json;odata=verbose",
success: function(data) {
console.log('complete');
},
error: function(data) {
console.log('fail');
}
}).promise();
arrDef.push(deferred);
}
return arrDef;
}
var getters = doSomething();
// use apply to call $.when
$.when.apply(this, getters).then(function() {
console.log('Final complete');
// correctly writes out all responses
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Within my code I have a function that depends on the result of an async call to an API endpoint. In order for the function to execute properly it needs to wait for the result of the call. So I've read up on async calls and from another Stack Overflow question I read that you should make use of callback functions to enable correct execution.
The code below is my attempt to make use of callbacks to allow my function to run successfully, but it doesn't work and at the moment I think the calls are messed up.
I'm not sure how I need to structure this code, but I first need the getInstructionType() call to return its value, then the GetValidationResult() call to return its value, and then the setValidationRowColor() function needs to execute.
getInstructionType(applicationNumber, function(result) {
getInstructionValidationResult(applicationNumber, function(type) {
setValidationRowColor(result);
});
});
function getInstructionValidationResult(applicationNumber) {
var url = //-snip-;
$.get(url, function(data) {
return data;
});
}
function getInstructionType(applicationNumber) {
var url = //-snip-;
$.get(url, function(data) {
return data;
});
}
You could add arguments to the functions which you can use as callbacks. Then you can call those when the AJAX request completes, something like this:
getInstructionType(applicationNumber, function(result) {
getInstructionValidationResult(applicationNumber, function(type) {
setValidationRowColor(result);
});
});
function getInstructionValidationResult(applicationNumber, callback) {
$.get(/*-snip-*/, function(data) {
// some custom logic to work with the response here...
callback && callback(data);
});
}
function getInstructionType(applicationNumber, callback) {
$.get(/*-snip-*/, function(data) {
// some custom logic to work with the response here...
callback && callback(data);
});
}
The alternative to callbacks (which are completely valid) are promises - which is really just another form or callbacks. Assuming you are using jQuery's $.get, you are already making use of Promises:
getInstructionType(applicationNumber, function(result) {
return getInstructionValidationResult(applicationNumber)
.then(function() {
setValidationRowColor(result)
})
});
function getInstructionValidationResult(applicationNumber) {
var url = //-snip-;
return $.get(url)
}
function getInstructionType(applicationNumber) {
var url = //-snip-;
return $.get(url)
}
Note that all I did was return the $.get and added a .then which accepts your callback inside getInstructionType
I have an array that can hold an unknown amount of indexes in it. Each index is used to send data with an ajax call. I am looping through with a for loop gathering the data from the successful call and pushing it into an empty array. At the end of the unknown amount of calls I then need to use that newly gathered array in my view. newDataArray is executed at the bottom before the loops are done and therefor it is still empty. How do I finish all the calls then do what is at the bottom?
If it helps, I am doing this in React with the Flux pattern. But the same issue may be done not in React. Here is a mock sample of what I am trying to do:
JS
case 'execute-calls':
//This is the new array to push to
var newDataArray = [];
//Url to call
var url = 'http://dev.markitondemand.com/Api/v2/Quote/jsonp';
for(let i = 0; i < payload.data.length; i++){
//given array of data that needs to be sent with call
let symb = { symbol: payload.data[i]};
$.ajax({
data: symb,
url: url,
dataType: "jsonp",
})
.done(function(data){
let updatedData = {
//...data that is stored from response
};
newDataArray.push(updatedData);
})
.fail(function(error){
//console.log(error);
});
}
//This will be updating the state object which is above the switch cases
//However this is ran before the end of the loops so newDataArray is empty
var updateTicker = {
updatedTicker: true,
updatedTickerSymbols: newDataArray
};
assign(stockData,updateTicker);
getStockData.emitChange();
break;
You can make use of the fact that $.ajax() actually returns a deferred object, and use it to create an array of deferreds. e.g.
var symbols = [1, 2, 3, 4];
var deferreds = symbols.map(function (symbol) {
return $.ajax({
url: 'http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp',
data: { symbol: symbol },
dataType: 'jsonp'
});
});
You can resolve multiple deferreds at once with $.when(). There is a complication however, $.when() expects a list of parameters rather than array. We can solve this by using Function#apply.
To add to the complication, the callback function is also called with a list of arguments. Since we don't know how many arguments there are, we'll use the arguments pseudo-array. And since arguments isn't an actual array, we'll loop through it by using Function#call on Array#prototype.
$.when.apply($, deferreds).done(function () {
Array.prototype.forEach.call(arguments, function (response) {
console.log(response[0].Message);
});
}).fail(function (jqXHR, textStatus, error) {
console.error(error);
});
[UPDATED to include fail() call]
If you're using ES6 this is much more elegant:
$.when(...deferreds).done((...responses) => {
responses.forEach((response) => {
console.log(response[0].Message);
});
});
When ever you are dealing with ajax calls and have to do some operations at the end of all async calls then better choice would be to use Callback functions.
Modifying your code to use the call back,
function AsyncLoopHandler(index) {
if (index > payload.data.length) {
// all the indexes have finished ajax calls do your next step here
var updateTicker = {
updatedTicker: true,
updatedTickerSymbols: newDataArray
};
assign(stockData, updateTicker);
getStockData.emitChange();
}
else {
//given array of data that needs to be sent with call
let symb = { symbol: payload.data[index] };
$.ajax({
data: symb,
url: url,
dataType: "jsonp",
})
.done(function (data) {
let updatedData = {
//...data that is stored from response
};
newDataArray.push(updatedData);
AsyncLoopHandler(index++); // call the function again with new index
})
.fail(function (error) {
//console.log(error);
});
}
}
Now for starting this recursive function just start it by passing the index 0.
AsyncLoopHandler(0);
So all the ajax calls will be executed one after the other as if its an synchronous requests, And the if check will see if all the indexes are complete and then run your logic. Let me know if this helps
suggest use promise, logic would like
var urls= [x,x,x,x];
var results = [];
var qs = $.map(urls,function(url){
return function(){
var deferred = Q.defer();
$.ajax({
success:function(){
results.push(url)
deferred.reslove();
},error:function(){
deferred.reslove();
}
})
return deferred;
}
})
Q.all(qs).then(function(){
console.log(results )
});
or use yield and co in new standard
https://github.com/kriskowal/q
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
The script should take the user's session via ajax and transfer it to other ajax requests that take the data for the charts. The first request succeeds, but others have not, becouse sessionId for them is undefined. Tried to wrap them in a function, but unfortunately nothing happened. What can be done?
var sessionId,
requestInWorkCount,
requestInWorkPower;
function getSession(){
$.getJSON("http://192.168.1.142/DashboardService.svc/web/jsonLoginUser?UserID=User1&UserPassword=123", {},
function(data) {
$.each(data, function (key, val) {
sessionId = val.toString();
return sessionId;
})
});
};
function getData(session){
$.getJSON("http://192.168.1.142/DashboardService.svc/web/jsonGetIndicator?SessionID="+session+"&IndNum=1", {},
function(data) {
$.each(data, function (key, val) {
requestInWorkCount = val;
return requestInWorkCount;
})
});
$.getJSON("http://192.168.1.142/DashboardService.svc/web/jsonGetIndicator?SessionID="+session+"&IndNum=2", {},
function(data) {
$.each(data, function (key, val) {
requestInWorkCount = val;
return requestInWorkPower;
})
});
};
$(document).ready(function(){
getSession();
getData(sessionId);
setInterval('show()',1000);
});
ajax call is async so your second ajax call is executed before the first completes thats the reason sessionId is undefined.
Use the success function of first ajax call and call GetData() in it.
Also you don't need to return sessionId
function getSession(){
$.getJSON("http://192.168.1.142/DashboardService.svc/web/jsonLoginUser?UserID=User1&UserPassword=123", {},
function(data) {
$.each(data, function (key, val) {
sessionId = val.toString();
getData(sessionId);
})
});
};
you call like this now:
$(document).ready(function(){
getSession();
});
The AJAX request are asynchronous and you cannot execute them sequentially.
An easy solution here would be to call getData() inside AJAX success block:
function getSession() {
$.getJSON("http://192.168.1.142/DashboardService.svc/web/jsonLoginUser?UserID=User1&UserPassword=123", {}, function(data) {
$.each(data, function (key, val) {
sessionId = val.toString();
getData(sessionId);
return sessionId;
});
});
};
You have to take the RESPONSE of the ajax request. You do not return it, I believe. But in your code you should perhaps do
sessionId = getSession();
getData(sessionId);
You forgot to dereference what it returned.
My script needs to fetch several json files on https://graph.facebook.com/xxxx, and retrieve a certain field from each json, then calculate summation.
My problem is how to print out the result after all getJSON done? With below code it will prints 0. Feel free to suggest any better approaches.
var result = 0;
$.each(urls, function (i, url) {
$.getJSON(url, function (json) {
result += json.field1;
})
});
alert(result);
Using jQuery 1.5 deferred objects:
Accumulate an array of the JQXHR objects returned by $.getJSON()
var jxhr = urls.map(function(url) {
return $.getJSON(url, function(json) {
result += json.field1;
})
});
and only $.when they're all .done():
$.when.apply($, jxhr).done(function() {
alert(result);
});
NB: this will accumulate result in the order that the AJAX calls complete, not in the order they're made.
It's not working as you are printing the result straight away, remember that the code where you concatenate the result is a callback so will fire after your alert.
On each callback you'll have to check if all have finished. replace the alert() call with your processing. :)
var result = 0;
var doneCount = 0;
$.each(urls, function (i, url) {
$.getJSON(url, function (json) {
doneCount++;
result += json.field1;
if (doneCount == urls.length) {
alert(result);
}
})
});