Multiple each and ajax requests - javascript

so this is my setup: I am calling a .each on a number of elements and after a few checks I send an ajax request with some JSON data and on success I apply the server response as an attribute to each element(it is usually an id). After that I push the id to an array.
The problem is that obviously ajax requests are asynchronous and the function that uses the array of element ids fires before all ajax have had time to finish.
I've tried with .when and .then but the callback function keeps getting fired way ahead of the ajax.
Here is how my code looks( I've removed some unnecessary parts):
var order = [];
function sub(selector){
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
$.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
})
}
$("#button").click(function(){
$.when(sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});

The problem is that when acts on deferred objects, however sub doesn't return anything so when fires right away. So what you need to do is to collect all the deferred objects returned by the ajax calls and return them:
var order = [];
function sub(selector){
var deferredList = []
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
var deferred = $.ajax({
type: "POST",
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
deferredList.push(deferred)
})
return deferredList;
}
$("#button").click(function(){
$.when.apply($,sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});
The reason to use apply and not when directly is that when doesn't accept array of objects as a parameter and apply provides us the work-around for this.

The argument to $.when() should be a Deferred, but sub() doesn't return anything. This version returns an array of all the Deferreds returned by $.ajax, and calls $.when with them all as arguments; it will then wait for all of them.
var order = [];
function sub(selector){
return selector.map(function(){
var out = {
"some":"random",
"stuff":"here"
};
return $.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
})
}
$("#button").click(function(){
$.when.apply(this, sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});

Your approach produces a whole lot of more server requests and will scale terribly. Since you want to wait for all results anyway, a much better solution would be to collect all data and send only one ajax request which returns an array of results for each data object.
Using a deferred object (as seen in other answers) then gives you the ability to use that result in a when statement.

try to use a callback-function in success:
var order = [];
function sub(selector, callback){
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
$.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
callback();
}
})
})
}
$("#button").click(function(){
sub($(".test"), function() { console.log(order) });
});

Add attribute async : false to your $.ajax - call. Then the calls are made in sequence after eachother.

Related

How to return multiple values from an ajax success event

I have two js files i.e. myJs1.js and myJs2.js .
From myJs1.js a method of myJs2.js is called.
I want to return r1 and r2 into results(in myJs1.js)
I have tried this:
I declared r1 and r2 variables before the ajax call and
after the ajax call I added:
return [r1,r2];
But it return r1 and r2 as undefined.
When I researched the issue I came across that adding async: false could work but it has so many issues (like browser freezing). Even so I tried it and still was not able to get the values of r1 and r2.
Note: I am uing AJAX for the first time so bear that in mind.
EDIT: There is an ajax call in Js1 in which on success event the method is called. I want to access the result to call another method in the js1
EDIT:LOOK HERE FOR THE CODE
myJS1:
function method()
{
$.ajax({
type: "GET",
dataType: "json",
url: "http://127.0.0.1:8000/***/***",
success: function(response){
result=methodOfmyJs2(response);
load1(r1); //r1 from result
load2(r2); //r2 from result
}
})
}
myJs2 :
function methodOfmyJs2(data)
{
$.ajax({
type: "GET",
data:SomeData,
dataType: "json",
url: "http://127.0.0.1:8000/***/***",
success: function(response){
r1=anotherMethodFromThisJS1(response);
r2=anotherMethodFromThisJS2(response);
result=[r1,r2]
}
})
}
I need to access the value of r1 and r2 to call load1 and load2 method of myJs1.
Ajax calls are asynchronous by default, meaning ajax call function jQuery.ajax() wont wait for the HTTP response to come back before returning.
To get the data after the HTTP response has arrived we have to provide a callback, that's success function. If you want to get this data inside another function just call that function inside success callback.
Following is the code:
//JS1.
function processResponse(r1, r2) {
// do processing here with r1 and r2
}
//JS2.
function methodOfmyJs2()
{
$.ajax({
type: "GET",
data:somedata,
dataType: "json",
url: "http://127.0.0.1:8000/****/****",
success: function(response){
r1=anotherMethodFromThisJS1(response);
r2=anotherMethodFromThisJS2(response);
//calling the success callback
processResponse(r1, r1);
}
});
}
There's another option if you really want to do it, you can make your Ajax call synchronous like below.
$.ajax({
type: "GET",
url: remote_url,
async: false,//now call is synchronous
success : function (data) {
}
});
Now jQuery.ajax() will wait till HTTP response has arrived, then you can return [r1, r2] from methodOfmyJs2().
However you should avoid making synchronous calls as it will make the JS thread wait freezing the UI.
You could use a callback instead.
[EDIT]
myJS1:
function method () {
$.ajax({
type: "GET",
dataType: "json",
url: "http://127.0.0.1:8000/***/***",
success: function (response) {
methodOfmyJS2(function (r1, r2) {
load1(r1);
load2(r2);
});
}
});
}
myJS2:
methodOfmyJs2 (callback) {
$.ajax({
type: "GET",
data: somedata,
dataType: "json",
url: "http://127.0.0.1:8000/****/****",
success: function (response) {
var r1 = anotherMethodFromThisJS1(response);
var r2 = anotherMethodFromThisJS2(response);
callback(r1, r2);
});
}
$.ajax returns promise, which can be chained with then
function getAjaxOutput() {
request1().then(function(data){
// get data from request 1 and pass to request 2
return request2(data);
})
.then(function(data){
// get data from request2
$('#output').text(JSON.stringify(data));
})
return false;
}
try it
https://jsfiddle.net/je7wf4ww/
and if u want to return plain result from getAjaxOutput - u simply can't (without making request sync of course) - u need to return promise which is a wrapper around ajax call and chain it again with then

Nesting ajax requests makes code hard to read

I usually like to organize my code so that one function fires a bunch of other
functions, like this:
/**
* GET MESSAGES:
*/
$(function() {
$.ajax({
url: '/messages',
method: 'GET',
dataType: 'json',
success: function(messages) {
if (messages.length > 0) {
keyedMessages = keyFork(messages);
reversedMessages = reverse(keyedMessages);
crushedMessages = crush(reversedMessages);
getFriendships(messages, crushedMessages);
}
mail.template.airmail();
}
});
});
However, if I need to do a second Ajax request inside one of the nested
functions I can't return the data because of the scope of the Ajax request
and it makes my code inconsistent and hard to follow, sort of broken up all over the place. For example, if one of the functions
invoked above fires a second Ajax request for friendships anything I write
after that will be broken from the communication chain due to the request and it seems impossible to return anything:
/**
* GET FRIENDSHIPS:
*/
function getFriendships(messages, crushedMessages) {
$.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
filteredCrushedMessages.forEach(function(filteredCrushedMessage) {
mail.sidebar.builder.messengers(filteredCrushedMessage);
});
mail.snailMail.onload();
}
});
}
If I try to return the data it doesn't work. Consequently I'll have to
continue invoking functions inside the nested request, every time I need to make another nested ajax request it breaks the chain. This makes my
code very hard to read. Are there any solutions to this problem or is
code that uses Ajax requests just hard to read?
You could store the data on a DOM element, then use jQuery Custom Events to get it done.
There's even support for passing arguments to your event handler:
https://learn.jquery.com/events/introduction-to-custom-events/#naming-custom-events
If I try to return the data it doesn't work.
Not appear jQuery promise returned from either function at Question ?
Try utilizing return statement , $.when.apply(this, arrayOfPromises) to return array of jQuery promise object from getFriendships
function getFriendships(messages, crushedMessages) {
return $.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
mail.snailMail.onload();
return $.when.apply($
, filteredCrushedMessages.map(function(filteredCrushedMessage) {
return mail.sidebar.builder.messengers(filteredCrushedMessage);
})
);
}
});
}
// e.g.,
getFriendships(messages, crushedMessages)
.then(function success() {
console.log(arguments)
}, function err(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})

Placing an ajax json object into a javascript variable

I've been trying to figure this one out since my earlier question.
I can receive the data, as I see it under resources using Develop > Show Web Inspector on safari. But I can't seem to assign it successfully to a variable to use later on.
<script>
function getData () {
$.ajax
({
type: "GET",
url: "https://myjirasite.com/jira/rest/api/2/project/ON/versions?",
dataType: 'jsonp',
//async: true,
beforeSend: function (xhr) {xhr.setRequestHeader('Authorization', make_base_auth("myusername", "mypassword"));},
success: function (){
//Attempt 1 at outputting the result to an alert.
alert(JSON.parse(data));
}
});
}
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return 'Basic ' + hash;
}
</script>
In a second attempt I assign the ajax call to a variable and attempt to print that out to an alert. No success. the alert is empty
var jqXHR = $.ajax
({
type: "GET",
url: "https://myjirasite/jira/rest/api/2/project/ON/versions?",
dataType: 'jsonp',
async: false,
beforeSend: function (xhr) {xhr.setRequestHeader('Authorization', make_base_auth("myusername", "mypassword"));},
success: function (data){
alert(JSON.parse(data));
}
});
alert(JSON.parse(jqXHR.responseText));
I know that the issue lies with ajax calls being asynchronous, but I can't figure out how to write the callback such that I can get the json data into a variable to use later in via a different function.
Don't set async: false, as this will block the browser whilst your Ajax request is processed.
Instead, you can use promises, or call a further function from within your success callback.
Something like:
function getData(){
return $.ajax({
type: "GET",
url: "https://myjirasite/jira/rest/api/2/project/ON/versions?",
dataType: 'jsonp',
beforeSend: function(xhr){
xhr.setRequestHeader('Authorization', make_base_auth("myusername", "mypassword"));
}
});
}
getData()
.done(function (data){
console.log(JSON.parse(data));
})
.fail(function(){
console.log("Error!");
});
<script>
var getData = function() {
$.ajax
({
type: "GET",
url: "https://myjirasite.com/jira/rest/api/2/project/ON/versions?",
dataType: 'jsonp',
//async: true,
beforeSend: function (xhr) {xhr.setRequestHeader('Authorization', make_base_auth("myusername", "mypassword"));},
success: function (){
//Attempt 1 at outputting the result to an alert.
alert(JSON.parse(data));
getData.data= JSON.parse(data);
}
});
}
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return 'Basic ' + hash;
}
setTimeout(function(){console.log(getData.data);}, 3000); // Fire after 3 seconds to get data.
</script>
I don't think $.ajax actually returns anything - but I could be wrong. Either way, that's not too important, because you shouldn't rely on the results of an ajax call being available immediately. Your alert statement is firing before the Ajax request is finished - it sounds like you know that already.
When leveraging asynchronous calls (ajax), its a best practice to have any logic that relies on the data returned from the call to be done in (or triggered by) a callback (or as #Jack Zelig mentions, promises). This is what success parameter of $.ajax is all about. It will get called once the request completes successfully. You can also define complete and error callbacks - which fire once the request is complete (regardless of status) and once the request fails respectively.
So to summarize, your best option is probably this:
var jqXHR = $.ajax
({
type: "GET",
url: "https://myjirasite/jira/rest/api/2/project/ON/versions?",
dataType: 'jsonp',
success: successHandler
});
function successHandler(data) {
alert(JSON.parse(data));
}
In this way, only once data is received will an alert be shown that will contain the data.

Call to ajax function within replace()

I have a function containing an ajax call:
function example(param, callback) {
$.ajax({
type: "GET",
url: param,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
callback(data);
}
});
}
I call it by:
example("http://www.example.com", function(result) {
// do something with result
})
But, I'd like to use example() in this context:
text.replace(/[regex not shown]/g, function(){
return RegExp.$1 + example(RegExp.$2); // does not work
});
i.e., the regex finds multiple matches, to which I then add example([whatever it matched]). Is there a way to integrate
example("http://www.example.com", function(result) {
// do something with result
})
into the text.replace()?
Thank you in advance!
You can't. That's because you are passing a to the .replace() method a function literal, so the replace method will take that function .toString() returned string (its source code) as an argument.
That is because .replace() method is synchronous and don't expect a callback as second argument, but a string, so it will convert any second argument to string if is not.
And if you actually call the function in the parameter, cause your function has no defined return value will parse "undefined" as second value.
But you can write your own asynchronous replace method and add it to the String prototype. I can't edit code in my phone, so when I get back to my computer I write it for you if you haven't figured out.
Edit:
Actually I was wrong, you can use a callback in the replace method. The problem is the way you are using an asynchronous call inside there. I don't know what are you exactly trying to do, so I hope this help you.
String.prototype.myReplace=function(re, o, p){
var v=[];
var t=this;
t.toString().replace(re, function(m){
if(m==RegExp.$1){v[1]=m;};
if(m==RegExp.$2){v[2]=m;};
});
$.ajax({
type: "GET",
url: v[2],
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
o[p]=t.toString().replace(re, function(m){
if(m==RegExp.$1){return v[1];};
if(m==RegExp.$2){return data.toString();};
});
}
});
};
And call it like this:
text.myReplace(/[regex not shown]/g, this/* or whatever object is */, 'text'});
Create a function to make the ajax call and handle the replacement of matches on a regular expression. Based on what you supplied above, this is the most modular approach assuming you want to perform these types of replacements more than once.
function replaceTextAfterAjax(str, regex, matchSendToServer, fn) {
var matches = regex.exec(str);
var externUrl = matches[matchSendToServer];
$.ajax({
type: "GET",
url: externUrl,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(json) {
fn(json.serverSideReplaceText, matches);
},
})
}
var text = "go to http://www.example.com";
replaceTextAfterAjax(text, /(go to) (.*)$/, 2, function(response, matches) {
text = matches[1] + ' ' + response;
// continue to use `text`
});
Notice that you should be keeping your use of RegExp local by invoking exec on the regular expression instance. This keeps your code thread-safe and prevents other methods from getting another call's RegExp.$N value.
friend, I don't understand your question clearly... you can try this below code... not sure will it work or not...
function example(param, callback) {
$.ajax({
type: "GET",
url: param,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
if(typeof callback!='undefined'){callback(data)}else{return data};
}
});
}
Try ConversationJS:
https://github.com/rhyneandrew/Conversation.JS
It allows you to make function calls in an entirely new way, essentially binding calls to events rather than making explicit calls. It would allow you to do exactly what you are trying to do in a much more "decoupled" manner, which means that it will also be easy to change and maintain in the future! Remember, nested dependencies are never good!

Returning result from jquery ajax request to a variable rather than firing a function

I'm experimenting with MCV using jquery. I'm making a call to an api, which returns data - what I want to do is return the data to a variable rather than call an additioanl function within my model. The following code doesn't do what I wish though (the_data = result). Any ideas how I can achieve this?
function lookForSomething()
{
var the_data = $.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
success: function(result) { return result; }
});
return the_data;
}
Many thanks,
J
If understand you correctly, you want the data returned by TheUrl to be the return value of the lookForSomething.
Technically, you could do this, with the async option:
function lookForSomething()
{
var the_data;
$.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
async : false,
success: function(result) { the_data = result; }
});
return the_data;
}
I strongly urge you not to do this. It's un-Javascript-like and it will lock up the user's browser while it's running. Much better to pass in a callback to the function and invoke it from success.
You are probably looking for deferred objects:
function lookForSomething()
{
var the_data;
$.when(
$.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
success: function(result) { the_data=result; }
});
).done(function() {
return the_data;
}).fail(function() {
return '';
});
}
Keep in mind that this is still asynchronous, so when you make a call for var ddd = lookForSomething();, ddd will not have the value you expect since the call may still be running. The only reason I brought up $.when() is because it seems like you require a lot of dependencies. $.when() allows you to wait for multiple ajax commands.

Categories