I'm performing two separate AJAX calls and I'd ultimately like for the results to be in the form of a number variable that I can manipulate. I've wrapped the execution of the functions within $(function() in an attempt to wait until both of the AJAX functions have returned their value so as not to begin to do the math before the results are returned, but it appears that's not working.
How can I ensure that the results are returned from two separate AJAX calls before the function manipulates their results?
// Collect Data Point P
function myCallbackP(result) {
var p = Math.round(result/3);
$('#past').html(p);
}
fooP(myCallbackP);
function fooP (callback){
$.ajax({
url: 'https://' + company + '.teamwork.com/' + actionP,
headers: {"Authorization": "BASIC " + window.btoa(key)},
}).done(function(response){
callback((response['todo-items']).length);
})
}
//Collect Data Point F
function myCallbackF(result) {
var f = (result);
$('#future').html(f);
}
fooF(myCallbackF);
function fooF (callback){
$.ajax({
url: 'https://' + company + '.teamwork.com/' + actionF,
headers: {"Authorization": "BASIC " + window.btoa(key)},
}).done(function(response){
callback((response['todo-items']).length);
})
}
//Math up data point P and F
$(function() {
var v = myCallbackP();
var y =myCallbackP;
var z = v/y;
console.log(z);
$('#ratio').html(z);
console.log('success?');
console.log( "ready!" );
});
You can use $.when()
// Collect Data Point P
function myCallbackP(result) {
var p = Math.round(result / 3);
$('#past').html(p);
}
function fooP(callback) {
return $.ajax({
url: 'https://' + company + '.teamwork.com/' + actionP,
headers: {
"Authorization": "BASIC " + window.btoa(key)
}
})
}
//Collect Data Point F
function myCallbackF(result) {
var f = (result);
$('#future').html(f);
}
function fooF(callback) {
return $.ajax({
url: 'https://' + company + '.teamwork.com/' + actionF,
headers: {
"Authorization": "BASIC " + window.btoa(key)
}
})
}
//Math up data point P and F
$(function() {
$.when(fooP(), fooF())
.then(function(p, f) {
console.log('success?');
myCallbackP(p[0]["todo-items"].length);
myCallbackF(f[0]["todo-items"].length);
var v = +$("#past").html();
var y = +$("#future").html();
var z = v / y;
console.log(z);
$('#ratio').html(z);
})
.fail(function(jqxhr, textStatus, errorThrown) {
console.log(errorThrown);
});
console.log("ready!");
});
I suggest you use jQuery Deferred and Promises like below
var ajax1 = fooP();
function fooP() {
var defObj = $.Deferred();
$.ajax({
url: 'https://' + company + '.teamwork.com/' + actionP,
headers: {
"Authorization": "BASIC " + window.btoa(key)
},
}).done(function(response) {
defObj.resolve(response);
});
return defObj.promise();
}
var ajax2 = fooF();
function fooF() {
var defObj = $.Deferred();
$.ajax({
url: 'https://' + company + '.teamwork.com/' + actionF,
headers: {
"Authorization": "BASIC " + window.btoa(key)
},
}).done(function(response) {
defObj.resolve(response);
});
return defObj.promise();
}
// when both calls are done
$.when(ajax1, ajax2).done(function(data1, data2) {
var p = Math.round(data1 / 3);
$('#past').html(p);
var f = (data2);
$('#future').html(f);
var z = p / f;
console.log(z);
$('#ratio').html(z);
console.log('success?');
console.log("ready!");
});
Related
I call a sync web services in my web site but there is no waiting of thier results.
I'm caling the function loadExtLayout in the function loadLayout , after that I'm calling the function loadLayout in other functions in the web site
HTTPRequestService.prototype.loadExtLayout = function(pathToLoad){
logManager.IHM_LOG_INFO("BEGIN HTTPRequestService loadExtLayout call pathToLoad="+JSON.stringify(pathToLoad));
var loadResult = null;
$.ajax({
async:false,
method: "GET",
url: pathToLoad
}).done(function(result){
loadResult = result;
}).fail(function(jqXHR, textStatus){
loadResult = null;
logManager.IHM_LOG_ERROR(new Error().stack+": "+"Error loading layout : " + pathToLoad + " (" + textStatus + ")\n");
});
logManager.IHM_LOG_INFO("END HTTPRequestService loadExtLayout call");
return loadResult;
}
GenericLayoutController.prototype.loadLayout = function(layoutName){
logManager.IHM_LOG_INFO("BEGIN loadLayout");
var loadResult = false;
var layoutContent = null;
try {
var httpService = new HTTPRequestService(this.AppId);
if(httpService != null){
layoutContent = httpService.loadExtLayout(layoutName);
console.log("layoutContent :" + layoutContent);
if ((layoutContent != null) && ($("#window_"+ this.AppId + "_" + this.WndId).attr("patternname") == this.patternName)) {
$("#window_"+ this.AppId + "_" + this.WndId).empty();
$("#window_"+ this.AppId + "_" + this.WndId).html(layoutContent);
loadResult = true;
} else if( layoutContent == null ){
logManager.IHM_LOG_ERROR("Error loading layout !");
}
} else {
logManager.IHM_LOG_ERROR("Error unable to create HTTPRequestService object : httpService is null !");
}
} catch(e) {
loadResult = false;
logManager.IHM_LOG_ERROR(new Error().stack+": "+e+"\n");
}
logManager.IHM_LOG_INFO("END loadLayout");
return loadResult;
}
if you using ajax param 'async: false', you gotta use callback(success) instead of promises, cause 'then' work asynchronously and 'return' executing before promise retriev data from server.
let data = null;
$.ajax({
async:false,
method: "GET",
url: pathToLoad,
success:(response)=>{data = response}
});
return data;
or you can do it asynchronously
HTTPRequestService.prototype.loadExtLayout = function(pathToLoad){
logManager.IHM_LOG_INFO("BEGIN HTTPRequestService loadExtLayout call pathToLoad="+JSON.stringify(pathToLoad));
let loadResult = new Promise((resolve,reject)=>{
$.ajax({
async:false,
method: "GET",
url: pathToLoad
}).done(function(result){
resolve(result);
}).fail(function(jqXHR, textStatus){
reject(textStatus);
loadResult = null;
logManager.IHM_LOG_ERROR(new Error().stack+": "+"Error loading layout : " + pathToLoad + " (" + textStatus + ")\n");
});
});
logManager.IHM_LOG_INFO("END HTTPRequestService loadExtLayout call");
return loadResult;
}
I have 2 lists in my Sharepoint : speeches and schools.
In my speeches form, I have a school field. I want to autocomplete this field with values (name, adress, city) from schools list.
Here's my code :
$(School_fieldID).autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term.replace(/ /g, "*\",\"*");
var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='and(\"*" + term + "*\",path:\"" + _spPageContextInfo.webAbsoluteUrl + "/Lists/Schools\")'&enablefql=true";
var executor = new SP.RequestExecutor(_spPageContextInfo.webAbsoluteUrl);
executor.executeAsync({
url: searchUrl,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
var results = jsonObject.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
var clientContext = new SP.ClientContext();
var schoolList = clientContext.get_web().get_lists().getByTitle('Schools');
response($.map(results, function (result) {
school = schoolList.getItemById(result.Cells.results[6].Value.split('=').pop());
clientContext.load(school, 'Title', 'Adress', 'City');
clientContext.executeQueryAsync(Function.createDelegate(this, function (schoolName, schoolAdress, schoolCity) {
schoolName = school.get_item('Title');
schoolAdress = school.get_item('Adress');
schoolCity = school.get_item('City');
}), Function.createDelegate(this, function (sender, args) {
alert('Error occured: ' + args.get_message());
}));
return {
label: schoolName + " (" + schoolAdress + " " + /*schoolCity + */ ")",
value: schoolName
};
}));
}
});
}
});
When I test this code, schoolName, schoolAdress et schoolCity are undefined because of asynchronous function executeQueryAsync.
So I think solution is in Promise or Callback, but I tried different solutions for a week, without success :-(
Please note I read carefully this post How do I return the response from an asynchronous call?, but can't find a good solution anyway...
Can anyone help me ?
Thanks in advance,
Florent
Considering you have to pass an array of objects to the response callback function and each one of the result is calling the async function clientContext.executeQueryAsync we can turn each one of them into a promise and pass them to Promise.all() which will wait for all of them to be resolved and returned them.
When they are all resolved, the objects will be inside the schoolObjectArray which then you can pass to the response function.
Is should work.
$(School_fieldID).autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term.replace(/ /g, "*\",\"*");
var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='and(\"*" + term + "*\",path:\"" + _spPageContextInfo.webAbsoluteUrl + "/Lists/Schools\")'&enablefql=true";
var executor = new SP.RequestExecutor(_spPageContextInfo.webAbsoluteUrl);
executor.executeAsync({
url: searchUrl,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
var results = jsonObject.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
var clientContext = new SP.ClientContext();
var schoolList = clientContext.get_web().get_lists().getByTitle('Schools');
Promise.all($.map(results, function (result) {
school = schoolList.getItemById(result.Cells.results[6].Value.split('=').pop());
clientContext.load(school, 'Title', 'Adress', 'City');
return new Promise(function(resolve,reject) {
clientContext.executeQueryAsync(Function.createDelegate(this, function (schoolName, schoolAdress, schoolCity) {
schoolName = school.get_item('Title');
schoolAdress = school.get_item('Adress');
schoolCity = school.get_item('City');
resolve({
label: schoolName + " (" + schoolAdress + " " + /*schoolCity + */ ")",
value: schoolName
});
}), Function.createDelegate(this, function (sender, args) {
reject('Error occured: ' + args.get_message());
}));
})
}))
.then(function(schoolObjectArray){
response(schoolObjectArray)
})
.catch(console.error);
}
});
}
});
I am trying to get share count of pininterest and below code is working well
var pi_like_count = 0;
PIUrl = "https://api.pinterest.com/v1/urls/count.json?url=" + url1 + "&format=jsonp" + '&callback=?'
$.getJSON(PIUrl, function (data) {
pi_like_count = data.count;
alert(pi_like_count +' pininterest');
});
but when I am trying to put below code issue is coming as
var pi_like_count = 0;
PIUrl = "https://api.pinterest.com/v1/urls/count.json?url=" + url1 + "&format=jsonp" + '&callback=?'
$.ajax({
method: 'GET',
url: PIUrl,
success: function (data) {
pi_like_count = data.count;
alert(pi_like_count + ' pininterest');
},
error: function (data) {
alert('error' + data.count + ' pininterest');
console.log(data);
},
async: false
});
Console.log error as
promise: function promise()
readyState: 4
responseText: "{\"error\":\"Invalid callback, use only letters, numbers, square brackets, underscores, and periods.\"}"
This issue is coming when I am using $.ajax, I had tried same to get facebook share count and is working well but pininterest is not working
more explaination
function GetScores(url) {
var FBUrl, TWUrl, LNUrl, GLUrl, PIUrl;
var url1 = "";
url1 = encodeURIComponent(url1 || url);
//Fetch counters from PInterest
var pi_like_count = 0;
PIUrl = "https://api.pinterest.com/v1/urls/count.json?url=" + url1 + "&format=jsonp" + '&callback=?'
$.ajax({
type: 'GET',
dataType: 'json',
url: PIUrl,
success: function (data) {
pi_like_count = data.count;
alert(pi_like_count + ' pininterest');
} ,
complete: function (jqXHR, data) {
pi_like_count = data.count;
alert(pi_like_count + ' pininterest complete');
},
error: function (req, status, error) {
alert('error');
},
async: false
});
//Fetch counters from Facebook
var fb_share_count = 0;
FBUrl = "https://graph.facebook.com/?id=" + url1 + "&format=json";
$.ajax({
type: 'GET',
url: FBUrl,
success: function (data) {
fb_share_count = data.share.share_count;
alert(fb_share_count+' facebook');
},
async: false
});
var totalshare = parseInt(fb_share_count) + parseInt(pi_like_count);
return totalshare;
}
Here Facebook count and total share count is get then after the pinterest count alert is showing i.e. when this function is calling second time then after pinterest is giving old count.
Try it:
function GetScores(url, onCountTotal) {
var FBUrl, TWUrl, LNUrl, GLUrl, PIUrl;
var url1 = "";
url1 = encodeURIComponent(url1 || url);
//Fetch counters from PInterest
var pi_like_count = 0;
PIUrl = "https://api.pinterest.com/v1/urls/count.json?url=" + url1 + "&format=jsonp" + '&callback=?';
$.ajax({
type: 'GET',
dataType: 'json',
url: PIUrl,
success: function (data) {
pi_like_count = data.count;
var fb_share_count = 0;
FBUrl = "https://graph.facebook.com/?id=" + url1 + "&format=json";
$.ajax({
type: 'GET',
dataType: 'json',
url: FBUrl,
success: function (data) {
fb_share_count = data.share.share_count;
var totalshare = parseInt(fb_share_count) + parseInt(pi_like_count);
onCountTotal(totalshare);
//alert(fb_share_count + ' facebook');
},
error: function (data) {
onCountTotal(-1);
},
async: true
});
},
error: function (req, status, error) {
onCountTotal(-1);
},
async: true
});
}
//EXAMPLE HERE CALL FUNCTION WITH CALLBACK
GetScores("http://www.google.com", function (count) {
alert("Count = " + count);
});
Here's what you could try using a CallBack :
var result = 0;
function handleData(data) {
result+=data.count;
}
function GetScores(url) {
var url1 = encodeURIComponent(url1 || url);
getFb(url1).done(handleData);
getPi(url1).done(handleData);
return result;
}
function getPi(url1){
var PIUrl = "https://api.pinterest.com/v1/urls/count.json?url=" + url1 + "&format=jsonp" + '&callback=?';
return $.ajax({
type: 'GET',
dataType: 'json',
url: PIUrl
});
}
function getFb(url1){
var FBUrl = "https://graph.facebook.com/?id=" + url1 + "&format=json";
return $.ajax({
type: 'GET',
url: FBUrl
});
}
You can adapt for every platform you need the shares from, just add another function in GetScores and handle properly the returned json
You could also do something like :
function getFb(url1, callback){
var FBUrl = "https://graph.facebook.com/?id=" + url1 + "&format=json";
$.ajax({
type: 'GET',
url: FBUrl,
success: callback
});
}
getFb(function(data){
result+=data.count;
});
Try to adapt your code depending on the result of your alerts
I have web methods that are called via AJAX in a .Net 4.0 web app. In many cases, the AJAX calls are made repeatedly in a for loop. My problem is, the information the web method is syncing to my server is time stamped and therefore must be synced in the order in which I am sending it to AJAX. Unfortunately, it seems whatever finishes first, simply finishes first and the time stamps are all out of order. I need to basically queue up my AJAX requests so that they execute in order rather than Asynchronously, which I know is the A in AJAX so this might be a totally dumb question.
How do I force the order of execution for AJAX calls done in a for loop?
Edit: Some code
for (var i = 0; i < itemCnt - 1; i++) {
try {
key = items[i];
item = localStorage.getItem(key);
vals = item.split(",");
type = getType(key);
if (type == "Status") {
var Call = key.substring(7, 17);
var OldStat = vals[0];
var NewStat = vals[1];
var Date1 = vals[2];
var Time1 = vals[3];
var miles = vals[4];
try {
stat(Call, OldStat, NewStat, Date1, Time1, miles, key);
}
catch (e) {
alert("Status " + e);
return;
}
}
else if (type == "Notes") {
var Call = key.substring(6, 16);
var Notes = item;
try {
addNotes(Call, Notes);
}
catch (e) {
alert("Notes " + e);
return;
}
}
else if (key == "StartNCTime" || key == "EndNCTime") {
var TechID = vals[0];
var Date = vals[1];
var Time = vals[2];
var Activity = vals[3];
var Location = vals[4];
var Type = vals[5];
try {
logTime(TechID, Date, Time, Activity, Location, Type,
}
catch (e) {
alert(key + ' ' + e);
return;
}
}
}
catch (e) {
alert(key + ' ' + e);
return;
}
}
function stat(Call, OldStat, NewStat, Date1, Time1, miles, key) {
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
url: "Service.asmx/update_Stat",
data: '{ CallNumber:"' + Call + '", OldStat:"' + OldStat + '", NewStat:"' + NewStat + '", Date1:"' + Date1 + '", Time1:"' + Time1 + '", Miles: "' + miles + '"}',
success: function (data) { },
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert("Sync Update Stat: " + err.Message);
location = location;
}
});
}
function logTime(TechID, Date, Time, Activity, Location, Type, key) {
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
url: "Service.asmx/nonCallTime",
data: '{ TechID:"' + TechID + '", Date1:"' + Date + '", Time1:"' + Time + '", Activity:"' + Activity + '", Location:"' + Location + '", Type: "' + Type + '"}',
success: function (data) { },
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert("Sync Non Call Time: " + err.Message);
location = location;
}
});
}
function addNotes(Call, Notes) {
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
url: "Service.asmx/addNote",
data: '{ Call:"' + Call + '", Notes:"' + Notes + '"}',
success: function (data) { },
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert("Sync Notes: " + err.Message);
location = location;
}
});
}
You have to use callbacks.
function ajax1(){
//..some code
//on ajax success:
ajax2();
}
//etcetera...
Or might I suggest using a javascript library like jQuery to synchronize your ajax requests for you.
set the third parameter in xmlhttp object's open method to false to make it synchronous.
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
A general pattern for making actions serial would be such:
function doAjax(data, cb) {
...
// when ready call cb
}
(function (next) {
var xhr = doAjax(data, next);
})(function (next) {
var xhr = doAjax(data, next);
})(function (next) {
doAjax(data);
});
Doing so in a for loop would require recursion.
(function next() {
if ( i < n ) {
doAjax(data[i++], next);
}
})();
OK I am building something that makes an ajax request to one server where it determines the url it needs to then make a new ajax request to another place. Everything is progressing thanks to all the help at SO =) .. however I am stuck again. I am struggling with getting the variables to return to the different functions as I need. The second (jsonp) request returns a json function which looks like :
jsonResponse(
{"it.exists":"1"},"");
and my code...
var img = "null";
var z = "null";
$(document).ready(function()
{
$.ajax({
type: "GET",
url: "connect.php",
dataType: "xml",
success: function parseXml(data)
{
$(data).find("ITEM").each(function()
{
query = $("SKU", this).text();
query = 'http://domain.com/' + query + '?req=exists,json';
img = $("SKU", this).text();
img = '<img src="http://domain.com/' + img + '">';
var date =$("LAST_SCAN" , this).text();
$.ajax({
url: query,
dataType: 'jsonp'
});
$("table").append('<tr>'+'<td>' + (date) + '</td>' + '<td>' + (z) + '</td>');
});
}
});
});
// function required to interpret jsonp
function jsonResponse(response){
var x = response["it.exists"];
// console.log(x);
if (x == 0) {
console.log("NO");
var z = "NO IMG";
}
if (x == 1) {
console.log(img);
//this only returns the first image path from the loop of the parseXml function over and over
var z = (img);
}
return z;
}
So I guess my problem is a two parter.. one how do I get the img variable to loop into that if statement and then once that works how can I return that z variable to be used in the first xml parser?
Try this synchronous approach:
var itemQueue = [];
$(document).ready(function ()
{
$.ajax({
type: "GET",
url: "connect.php",
dataType: "xml",
success: function parseXml(data)
{
itemQueue= $(data).find("ITEM").map(function ()
{
return {
sku: $("SKU", this).text(),
date: $("LAST_SCAN", this).text()
};
}).get();
getNextItem();
}
});
});
function getNextItem()
{
var item = itemQueue[0];
var query = "http://domain.com/" + item.sku + "?req=exists,json";
$.ajax({
url: query,
dataType: 'jsonp'
});
}
function jsonResponse(response)
{
var item = itemQueue.shift();
if (itemQueue.length)
{
getNextItem();
}
var x = response["it.exists"];
var z = x == "0" ? "NO IMG" : "<img src=\"http://domain.com/" + item.sku + "\">";
$("table").append("<tr><td>" + item.date + "</td><td>" + z + "</td>");
}
Store 'date' in a global variable, and move the logic to append HTML elements into the jsonResponse function. You cannot return control flow from jsonResponse because it's called asynchronously, but you can continue doing anything you'd like from that function.