JavaScript promises with nested AJAX calls are not working - javascript

On my code I hava a function with 3 nested AJAX calls, in order for it to work I had to set Async=false.
As I have read that Async=false is deprecated I replaced the Async=false with promises.
This is my function before I edited it:
self.getOrders = function (name) {
var orders= [];
var order= function (item, type1, type2) {
var self = this;
self.order= item;
self.type1= type1;
self.type2= type2;
}
$.ajax({
url: "/API/orders/" + name,
type: "GET",
async: false,
success: function (orderResults) {
var mappedOrders = $.map(orderResults, function (orderItem) {
$.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET",
async: false,
success: function (property1Results) {
$.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET",
async: false,
success: function (property2Results) {
orders.push(new order(orderItem, property1Results, property2Results));
}
});
}
});
})
}
});
return orders;
This function worked perfectly, I got the data end everything worked fine.
Then I changed the function to use promises instead of Async=false,
this is the edited function, with promises:
//The begin of the function- same as first one
var orders= [];
var firstPromise = $.ajax({
url: "/API/orders/" + name,
type: "GET"
});
$.when(firstPromise).done(function (orderResults) {
var mappedOrders = $.map(orderResults, function (orderItem) {
var secondPromise = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET"
});
$.when(secondPromise).done(function (property1Results) {
var thirdPromise = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET"
});
$.when(thirdPromise).done(function (property2Results) {
orders.push(new order(orderItem, property1Results, property2Results));
});
});
});
});
return orders;
And the function call:
self.populateOrders = function (name) {
var mappedOrders = $.map(self.service.getOrders(name), function (item) {
return new Order(item)
});
self.orders(mappedOrders);
}
The new function is not working, I'm getting back from the firstPromise a wrong json with backslashes, and the returned orders object is empty.
Any idea what am I doing wrong? I spent so much time on it but couldn't figure it out.
Thanks in advance.

Nested ajax calls inside a loop is a hell to manage. You can do it like this.
Create a promise to notify the caller when the whole process is finished
Wait for all the inner ajax calls to resolve
Resolve you main promise to notify the caller
self.getOrders = function (name) {
var mainDeferred = $.Deferred();
var orders = [];
var order = function (item, type1, type2) {
var self = this;
self.order = item;
self.type1 = type1;
self.type2 = type2;
}
$.ajax({
url: "/API/orders/" + name,
type: "GET",
success: function (orderResults) {
var innerwait = [];
var mappedOrders = $.map(orderResults, function (orderItem) {
var ajax1 = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET"
});
var ajax2 = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET"
});
$.when(ajax1, ajax2).done(function (property1Results, property2Results) {
orders.push(new order(orderItem, property1Results[0], property2Results[0])))
});
innerwait.push(ajax1, ajax2);
});;
$.when.apply(null, innerwait) //make sure to wait for all ajax requests to finish
.done(function () {
mainDeferred.resolve(orders); //now that we are sure the orders array is filled, we can resolve mainDeferred with orders array
});
}
});
return mainDeferred.promise();
}
self.populateOrders = function (name) {
self.service.getOrders(name).done(function (orders) { //use .done() method to wait for the .getOrders() to resolve
var mappedOrders = $.map(orders, function (item) {
return new Order(item)
});
self.orders(mappedOrders);
});
}
In the example, note that I use $.when.apply() to wait for an array of deferreds.

A bug recently introduced in chrome 52 (august 2016) can cause this kind of behavior : answers for nested requested are ignored.
Hoppefully, it will not last long.
https://bugs.chromium.org/p/chromium/issues/detail?id=633696
Try to add cache: false

Related

Javascript response and ajax request

I have the following:
function wikiAjax (searchURL) {
return Promise.resolve($.ajax({
url: searchURL,
jsonp: "callback",
dataType: 'jsonp',
xhrFields: {
withCredentials: true
},
}));
}
$(".search-form").submit(function() {
var searchText = $('#search').val();
var searchURL = "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=search&gsrsearch=" + searchText + "&gsrlimit=15&prop=extracts&exsentences=3&exintro=&explaintext&exlimit=max&callback=JSON_CALLBACK";
console.log(searchURL);
var wikiResponse = wikiAjax(searchURL);
wikiResponse.then(function(data) {
alert(data);
}, function() {
alert("The call has been rejected");
});
});
But i get an answer only if I put a breakpoint somewhere (e.g. at the wikiResponse.then line).
Then it looks like the code is executed before the call returns the result but why? Isn't the promise set properly?
Many thanks in advance.
I think what might be happening here is the browser is executing the default submit event on the form in addition to the ajax call. The result is that the window is unloaded and reloaded.
Try putting:
event.preventDefault();
in the handler.
$(".search-form").submit(function(event) {
event.preventDefault();
var searchText = $('#search').val();
var searchURL = "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=search&gsrsearch=" + searchText + "&gsrlimit=15&prop=extracts&exsentences=3&exintro=&explaintext&exlimit=max&callback=JSON_CALLBACK";
console.log(searchURL);
var wikiResponse = wikiAjax(searchURL);
wikiResponse.then(function(data) {
alert(data);
},
function() {
alert("The call has been rejected");
}
);
});
I think Promise.resolve() is an ES6 feature so unless you explicitly make sure you support it it should not work.
But, lucky for you $.ajax() return a promise in the following format:
var promise = $.ajax({
url: "/myServerScript"
});
promise.done(mySuccessFunction);
promise.fail(myErrorFunction);
(and not with then() and catch() like was written in your code)
It's unnecessary to do Promise.resolve here, because the $.ajax call already returns a promise.
Try this:
function wikiAjax (searchURL) {
return $.ajax({
url: searchURL,
jsonp: "callback",
dataType: 'jsonp',
xhrFields: {
withCredentials: true
}
});
}
$(".search-form").submit(function() {
var searchText = $('#search').val();
var searchURL = "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=search&gsrsearch=" + searchText + "&gsrlimit=15&prop=extracts&exsentences=3&exintro=&explaintext&exlimit=max&callback=JSON_CALLBACK";
console.log(searchURL);
var wikiResponse = wikiAjax(searchURL);
wikiResponse.done(function(data) {
alert(data);
}).fail(function(err) {
alert("The call has been rejected");
});
});
This is a working (and modified to show) plunker: https://plnkr.co/edit/qyc4Tu1waQO6EspomMYL?p=preview

Return variable from Javascript function

I can`t return result of this function.
function get_duration() {
var a = '';
$.ajax({
url: "http://gdata.youtube.com/feeds/api/videos?q=3KMz3JqRByY&max-results=50& format=5,1,6",
dataType: "jsonp",
success: function (data) {
re2 = /seconds='(\d+)'/ig;
while (re.exec(data) != null) {
a = re2.exec(data);
}
}
});
return a;
}
You have to use return inside the success callback since, A in Ajax is asynchronous.
Like this:
function get_duration() {
var a = '';
$.ajax({
url: "http://gdata.youtube.com/feeds/api/videos?q=3KMz3JqRByY&max-results=50& format=5,1,6",
dataType: "jsonp",
success: function (data) {
re2 = /seconds='(\d+)'/ig;
while (re.exec(data) != null) {
a = re2.exec(data);
}
return a;
}
});
}
But, this function isn't guaranteed to return. You'll have to use a callback function kind of thing.

Javascript: Setting class property from ajax success

I have a "class"/function called Spotlight. I'm trying to retrieve some information through ajax and assign it to a property of Spotlight. Here is my Spotlight class:
function Spotlight (mId,mName) {
this.area = new Array();
/**
* Get all area information
*/
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
this.area = data;
}
});
}
}
I have assigned the object to an array, and it would be difficult to get to it from within Spotlight, so I'm hoping to access everything using 'this.' It appears though that the success function is outside of the class, and I don't know how to make it inside the class.
Is there a way to get the data into the class property using this.area rather than Spotlight.area?
The value of this is dependent on how each function is called. I see 3 ways around this problem:
1. Creating an alias to this
var that = this;
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
that.area = data;
}
});
};
2. Using jQuery .ajax context option
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
context : this,
success: function (data) {
this.area = data;
}
});
};
3. Using a bound function as the callback
this.getAreaSuccess = function (data) {
this.area = data;
};
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: this.getAreaSuccess.bind(this)
});
};
Well Spotlight.area wouldn't work anyway. You just need to preserve the outer this:
this.area = [];
var theSpotlight = this;
and then in the callback:
theSpotlight.area = data;
When inside the success function, this corresponds to the scope of the success function.
function Spotlight (mId,mName) {
this.area = [];
var scope = this;
/**
* Get all area information
*/
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
scope.area = data;
}
});
}
}

get response from FB Api JavaScript

i try to get a function return in combination with facebook api reqeust.
var g_ret = true;
function uploadImagesFbCounter(anz){
var gid='';
$("div[id ^= 'gallerydetail']").each(function (i) {
gid = this.id.split('-');
gid = parseInt(gid[1]);
})
if(gid==0) return true;
FB.api('/me', function(response) {
  //console.log(response);
  var uid = response.id;
if(!anz){
g_ret = $.ajax({
type: "POST",
async:false,
url: "api/gallerie_anz_speich.php",
data: "uid="+uid+"&op=get&gid="+gid
});
if(g_ret.response >= 20) {
g_ret = false;
}
} else {
g_ret = $.ajax({
type: "POST",
async:false,
url: "api/gallerie_anz_speich.php",
data: "uid="+uid+"&op=set&gid="+gid
});
//console.log(g_ret.response);
g_ret = '<span style="padding:0 5px;">Noch '+(20-g_ret.response)+'Fotos</span>';
console.log(g_ret);
}
});
return g_ret;
}
what ever I do, i get an empty response.... please help!
The API you're using is asynchronous. You can't return a value from your function like that; it's just impossible in such a situation.
Instead, write your API so that its clients pass it a callable function. Inside the Facebook API callback, you can call that function and pass it that "g_ret" string.
function uploadImagesFbCounter(anz, callback){
// ...
FB.api('/me', function(response) {
// ...
callback(g_ret);
});
}
Then when you call your function, instead of:
var result = uploadImagesFbCounter( whatever );
// ... do something with result ...
you'd do this:
uploadImagesFbCounter( whatever, function( result ) {
// ... do something with result ...
});
Getting the user information from Facebook's servers is asynchronous. This means, any code you write after FB.api() does not wait for Facebook to respond. Your browser is not blocked just to wait for Facebook's servers. This is the same concept as AJAX, which I believe you are familiar with because I see you use it in your code.
The common way to "get a return value" from an asynchronous server request is to use a callback function.
function uploadImagesFbCounter(anz, onSuccess){
var gid='';
$("div[id ^= 'gallerydetail']").each(function (i) {
gid = this.id.split('-');
gid = parseInt(gid[1]);
})
if(gid==0) return true;
FB.api('/me', function(response) {
//console.log(response);
var uid = response.id;
if(!anz){
g_ret = $.ajax({
type: "POST",
async:false,
url: "api/gallerie_anz_speich.php",
data: "uid="+uid+"&op=get&gid="+gid
});
if(g_ret.response >= 20) {
g_ret = false;
}
} else {
g_ret = $.ajax({
type: "POST",
async:false,
url: "api/gallerie_anz_speich.php",
data: "uid="+uid+"&op=set&gid="+gid
});
//console.log(g_ret.response);
g_ret = '<span style="padding:0 5px;">Noch '+(20-g_ret.response)+'Fotos</span>';
console.log(g_ret);
}
onSuccess(g_ret);
});
}
uploadImagesFbCounter(
whateverAnzIs,
function(g_ret) {
console.info(g_ret);
}
);

Get HTML values from AJAX GET

I have this code:
$.ajax({
type: 'get',
url: 'https://......./confirma.asp',
data: $('.newform').serialize(),
dataType: 'jsonp',
beforeSend: function () {
$('.ajax-loader').slideToggle();
},
success: function (resposta) {
alert(resposta); // not work
$('.ajax-loader').slideToggle();
}
});
I get this response from ajax GET (firebug):
CODRET=1&MSGRET=JA CONFIRMADA
How I get this values? For example:
resposta['CODRET'];
or
resposta.CODRET
Because I need set in another JQuery function( );
Well that looks like a query string. Here is a modified version of this answer:
function parseQueryString(qs) {
var urlParams = {};
var e,
a = /\+/g, // Regex for replacing addition symbol with a space
r = /([^&=]+)=?([^&]*)/g,
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
q = qs.substring(1);
while (e = r.exec(q))
urlParams[d(e[1])] = d(e[2]);
return urlParams;
}
console.log(parseQueryString("CODRET=1&MSGRET=JA CONFIRMADA"));
http://jsfiddle.net/GphYj/
probably you should split them:
$.ajax({
type: 'get',
url: 'https://ecommerce.redecard.com.br/pos_virtual/confirma.asp',
data: $('.newform').serialize(),
beforeSend: function () {
$('.ajax-loader').slideToggle();
},
success: function (data) {
var codret = data.split('&')[0].split('=')[1];
var msgret = data.split('&')[1].split('=')[1];
$('.ajax-loader').slideToggle();
}
});
If you can't change the server code do this
function QueryStringToJsonObject(queryString)
{
var queries = {};
decodeURIComponent(queryString).replace(/([^=]+)=([^&]+)/g,
function(all, key, value) {
queries[key.replace(/^&/,'')] = value;
}
);
return queries;
}
and then:
QueryStringToJsonObject(responseText) ["CODRET"] //1
Otherwise consider returning JSON to http request.

Categories