JavaScript callback function when working withing a loop - javascript

This is what the code below does:
Goes to a table in a database and retrieves some search criteria I will send to Google API (the PHP file is getSearchSon.php)
After having the results, I want to loop around it, call the Google API (searchCriteriasFuc) and store the results in an array
The last part of the code is doing an update to two different tables with the results returned from Google API (updateSearchDb.php)
In my code, I am using setTimeout in a few occasions which I don't like. Instead of using setTimeout, I would like to properly use callback functions in a more efficient way (This might be the cause of my problem) What is the best way of me doing that?
$(document).ready(function() {
$.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'Text',
/*data: { }, */
error: function(a, b, c) { alert(a+b+c); }
}).done(function(data) {
if(data != "connection")
{
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
var length = search_criterias.length;
var arrXhr = [];
var totalResultsArr = [];
var helperFunc = function(arrayIndex)
{
return function()
{
var totalResults = 0;
if (arrXhr[arrayIndex].readyState === 4 && arrXhr[arrayIndex].status == 200)
{
totalResults = JSON.parse(arrXhr[arrayIndex].responseText).queries.nextPage[0].totalResults;
totalResultsArr.push(totalResults);
}
}
}
var searchCriteriasFuc = function getTotalResults(searchParam, callback)
{
var searchParamLength = searchParam.length;
var url = "";
for(var i=0;i<searchParamLength;i++)
{
url = "https://www.googleapis.com/customsearch/v1?q=" + searchParam[i] + "&cx=005894674626506192190:j1zrf-as6vg&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM&dateRestrict=" + date_length;
arrXhr[i] = new XMLHttpRequest();
arrXhr[i].open("GET", url, true);
arrXhr[i].send();
arrXhr[i].onreadystatechange = helperFunc(i);
}
setTimeout(function()
{
if (typeof callback == "function") callback.apply(totalResultsArr);
}, 4000);
return searchParam;
}
function callbackFunction()
{
var results_arr = this.sort();
var countResultsArr = JSON.stringify(results_arr);
$.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'Text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
}).done(function(data) {
var resultsDiv = document.getElementById("search");
if(data == "NORECORD") resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
else resultsDiv.innerHTML = 'Update was successful';
}); //end second ajax call
}
//llamando funcion principal
var arrSearchCriterias = searchCriteriasFuc(search_criterias, callbackFunction);
}
else
{
alert("Problem with MySQL connection.");
}
}); // end ajax
});

How you did it in 2015
Callbacks are things of the past. Nowadays you represent result values of asynchronous tasks with Promises. Here is some untested code:
$(document).ready(function() {
$.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'text'
/*data: { }, */
}).then(function(data) {
if (data == 'connection') {
alert("Problem with MySQL connection.");
} else {
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
return Promise.all(search_criterias.map(function(criteria) {
return $.ajax({
url: "https://www.googleapis.com/customsearch/v1"
+ "?q=" + criteria
+ "&cx=005894674626506192190:j1zrf-as6vg"
+ "&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM"
+ "&dateRestrict=" + date_length,
type: 'GET'
});
})).then(function(totalResultsArr) {
totalResultsArr.sort();
var countResultsArr = JSON.stringify(totalResultsArr);
return $.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
});
}).then(function(data) {
var resultsDiv = document.getElementById("search");
if(data == "NORECORD") {
resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
} else {
resultsDiv.innerHTML = 'Update was successful';
}
});
}
}).then(null, function() {
alert('Some unexpected error occured: ' + e);
});
});
This is how you do it in 2016 (ES7)
You can just use async/await.
$(document).ready(async() => {
try {
var data = await $.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'text'
/*data: { }, */
});
if (data == 'connection') {
alert("Problem with MySQL connection.");
} else {
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
var totalResultsArr = await Promise.all(
search_criterias.map(criteria => $.ajax({
url: "https://www.googleapis.com/customsearch/v1"
+ "?q=" + criteria
+ "&cx=005894674626506192190:j1zrf-as6vg"
+ "&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM"
+ "&dateRestrict=" + date_length,
type: 'GET'
}))
);
totalResultsArr.sort();
var countResultsArr = JSON.stringify(totalResultsArr);
var data2 = await $.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
});
if(data2 == "NORECORD") {
resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
} else {
resultsDiv.innerHTML = 'Update was successful';
}
}
} catch(e) {
alert('Some unexpected error occured: ' + e);
}
});
UPDATE 2016
Unfortunately the async/await proposal didn't make it to the ES7 specification ultimately, so it is still non-standard.

You could reformat your getTotalResults function in the following matter, it would then search rather sequential, but it should also do the trick in returning your results with an extra callback.
'use strict';
function getTotalResults(searchParam, callback) {
var url = "https://www.googleapis.com/customsearch/v1?q={param}&cx=005894674626506192190:j1zrf-as6vg&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM&dateRestrict=" + (new Date()).getTime(),
i = 0,
len = searchParam.length,
results = [],
req, nextRequest = function() {
console.log('received results for "' + searchParam[i] + '"');
if (++i < len) {
completeRequest(url.replace('{param}', searchParam[i]), results, nextRequest);
} else {
callback(results);
}
};
completeRequest(url.replace('{param}', searchParam[0]), results, nextRequest);
}
function completeRequest(url, resultArr, completedCallback) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
var totalResults = JSON.parse(this.responseText).queries.nextPage[0].totalResults;
resultArr.push(totalResults);
completedCallback();
}
};
req.send();
}
getTotalResults(['ford', 'volkswagen', 'citroen', 'renault', 'chrysler', 'dacia'], function(searchResults) {
console.log(searchResults.length + ' results found!', searchResults);
});
However, since you already use JQuery in your code, you could also construct all the requests, and then use the JQuery.when functionality, as explained in this question
Wait until all jQuery Ajax requests are done?

To get the callback execute after google calls are finished you could change:
var requestCounter = 0;
var helperFunc = function(arrayIndex)
{
return function()
{
if (arrXhr[arrayIndex].readyState === 4 && arrXhr[arrayIndex].status == 200)
{
requestCounter++;
totalResults = JSON.parse(arrXhr[arrayIndex].responseText).queries.nextPage[0].totalResults;
totalResultsArr.push(totalResults);
if (requestCounter === search_criterias.length) {
callbackFunction.apply(totalResultsArr);
}
}
}
}
then remove the setTimeout on searchCreteriaFuc.
Consider using promises and Promise.all to get all much cleaner :D

Related

jQuery runs in background, but not in foreground

I have this code fragment:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid); //here we trying to obtain key
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
}
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
But when i call getKey(kaid) function:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
return tret;
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Browsers don't continue do function getKey(), they do next commands in parent function, i don't know why they ignore web server answer and don't let function return server response :(
in general, an ajax call is asynchronous. That means, a sequence like
var a = 0;
a = getAwithAjaxFromServer(...);
console.log(a);
will immediately print "0" while the ajax is still runnng.
Your entire logic with cleyand encryption_state has to be put into the done function:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid);
}
}
and in your ajax:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
.... PUT ALL THE LOGIC HERE .....
}
});
}
You must understand asynchronous mechanism in javascript to continue calling ajax. There are a lot of resources and stackoverflow questions. For example: https://www.pluralsight.com/guides/front-end-javascript/introduction-to-asynchronous-javascript
So, you can convert the code so:
if(!encryption_state){
var serverKeyCallback = function(cKey) {
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
};
var localKeyCallback = function(cKey) {
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
manageKey(cKey, aid, serverKeyCallback, localKeyCallback);
}
function manageKey(cKey, kaid, serverKeyCallback, localKeyCallback) {
if(cKey=="" || cKey==null) {
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
serverKeyCallback(tret);
localKeyCallback(tret);
}
});
}
else {
localKeyCallback(cKey);
}
}
Defining two encapsulated pieces of code, one to execute after serverResponse, and the other to execute after the serverResponse or when you have the cKey locally stored. I haven't tested the code, but it must work as you expect.

How to trigger callbacks jquery 3.1.0

What I like is the best way to handle my .fail() & .done() when my ajax request returns with a assoc array that I parse.
This is my current code and my current problem is .fail(). always firing.
Note: I tested my something.php and its giving me the right response when it fail or when it succeeded this is the actual response to my something.php
Fail :
{
"ac":"failed"
}
Success :
{
"alias": "cd9d0e2e",
"sso": "http://somethin.com/home/site/cd9d0e2e?dm_sso=2!dsa654654sa56d FGfre4f645465fTIxYWE3NGZkMzk0NGM3NzIyMWFhNWQyMTgifQ",
"ru": "http://somethin.com/login/resetpwd?uuid=asd1as3d1as321d-4370-be5d-123a3s2d1a3sd13a2s",
"ac": "something#sample.com",
"fn": "Fish",
"ln": "Fillet"
}
$(document).ready(function(){
$('#btn-create').click(function(e){
e.preventDefault();
var cSite = createSite();
cSite.done(sendMail).fail(failOption).always(alwaysOption);
}
});
function createSite() {
var promise = $.Deferred();
$.ajax({
url: 'something.php',
method: 'POST',
data:"template_id="+template_id+"&original_url="+original_url+"&email="+email+"&first_name="+first_name+"&last_name="+last_name
}).then(function(data) {
var dataa = JSON.parse(data);
//debugger;
if(dataa.ac === 'failed') {
promise.reject(dataa);
} else {
promise.resolve(dataa);
}
});
return promise;
}
function sendMail(dataa) {
console.log(dataa);
}
You can return the promise form your createSite function.
var cSite = createSite(); and then use with .then, .done, .always or .fail etc.
$(document).ready(function() {
$('#btn-create').click(function(e) {
e.preventDefault();
var cSite = createSite();
cSite.done(function(resp) {
var dataa = JSON.parse(resp);
sendMail(dataa);
}).fail(failOption).always(alwaysOption);
});
});
function createSite() {
var promise = $.ajax({
url: 'something.php',
method: 'POST',
data: "template_id=" + template_id + "&original_url=" + original_url + "&email=" + email + "&first_name=" + first_name + "&last_name=" + last_name
})
return promise;
}
function sendMail(dataa) {
console.log(dataa);
}
Okay I figure it out now .. this is the code that works now.
$(document).ready(function(){
$('#btn-create').click(function(e){
//debugger;
e.preventDefault();
$(this).html('Creating Site');
var template_id = $("#template_id").val();
var original_url = $("#original_url").val();
var email = $("#email").val();
var first_name = $("#first_name").val();
var last_name = $("#last_name").val();
$.ajax({
url: 'create-site-con.2.php',
method: 'POST',
data:"template_id="+template_id+"&original_url="+original_url+"&email="+email+"&first_name="+first_name+"&last_name="+last_name
}).done(function(resp) {
var dataa = JSON.parse(resp);
if (dataa.ac === "failed"){
failOption(dataa);
}
else{
sendMail(dataa);
}
});
});//click
});//doc ready

How to return a parent function when the function is recursive Javascript

I've been completing FreeCodeCamp and have given myself the task of fetching an image from the Wikipedia API. I am so close but I am just having trouble with this recursive function.
I'm having some trouble with an ajax request. I want the whole success function to return when obj===label. However, it is only returning one instance of findObjByLabel().
What can I do to make the success function completely return as soon as the label is found?
var wikiUrl = "https://en.wikipedia.org/w/api.php?action=query&format=json&titles=India&prop=pageimages&pithumbsize=300&callback=?";
// this retrieves info about the wikiUrlImg
$.ajax( {
url: wikiUrl,
data: {
format: 'json'
},
dataType: 'json',
type: 'GET',
headers: { 'Api-User-Agent': 'Example/1.0' },
success: function(data) {
console.log("wiki api success");
var findLabel = findObjByLabel(data,"India",1);
function findObjByLabel(obj, label, iterrations){
var itterationLimit = "9";
if (iterrations < itterationLimit){
for(var i in obj){
if(obj === label){
console.log(">>>>>>>>>>>>>>>>>>>>>>> !!!its the label!!! <<<<<<<<<<<<<<<<<<<<<<<<");
// ****************I want the success function to return here! ****************
return "something";
}else{
console.log(">>>>>>>>>>>>>>>>>>>>>>>its not the label<<<<<<<<<<<<<<<<<<<<<<<<");
console.log("i= " + i);
if(obj.hasOwnProperty(i)){
iterrations+=1;
console.log("obj[i] : " + obj[i]);
var foundLabel = findObjByLabel(obj[i], label, iterrations);
}
}
}
}
}//end of findObjByLabel function
}, //end of success
error: function(){
console.log("failure of getWiki api");
}
});
Substitute obj[i] for obj at if condition, use break within if statement, place return statement outside of for loop
var wikiUrl = "https://en.wikipedia.org/w/api.php?action=query&format=json&titles=India&prop=pageimages&pithumbsize=300&callback=?";
// this retrieves info about the wikiUrlImg
$.ajax({
url: wikiUrl,
data: {
format: 'json'
},
dataType: 'json',
type: 'GET',
headers: {
'Api-User-Agent': 'Example/1.0'
},
success: function(data) {
console.log("wiki api success");
var findLabel = findObjByLabel(data, "India", 1);
function findObjByLabel(obj, label, iterrations) {
var itterationLimit = "9";
if (iterrations < itterationLimit) {
for (var i in obj) {
if (obj[i] === label) {
console.log(">>>>>>>>>>>>>>>>>>>>>>> !!!its the label!!! <<<<<<<<<<<<<<<<<<<<<<<<");
// ****************I want the success function to return here! ****************
break; // break `for` loop
} else {
console.log(">>>>>>>>>>>>>>>>>>>>>>>its not the label<<<<<<<<<<<<<<<<<<<<<<<<");
console.log("i= " + i);
if (obj.hasOwnProperty(i)) {
iterrations += 1;
console.log("obj[i] : " + obj[i]);
var foundLabel = findObjByLabel(obj[i], label, iterrations);
}
}
}
}
return "something"; // return `"something"`
} //end of findObjByLabel function
console.log(findLabel); // "something"
}, //end of success
error: function() {
console.log("failure of getWiki api");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Why don't work my function xmlParser(). Help me please

Hello everybody. I have a problem with my code. I use the jquery framework. When I want to call $.ajax(requestOptions), function xmlParser(xml) don't working.
I try to find a resolve this problem, but I can't nothing find.
$(document).ready(function () {
var requestOptions = {
type: "GET", //The method
url: "Course_Valute_02-07-2014.xml", //It is reference on xml file
dataType: "xml", //The type of data
crossDomain: true, //Allow to do the cross-domain request
success: xmlParser //Calling function
};
function xmlParser(xml) {
$("#load").fadeOut();
$(xml).find("Valute").each(function() {
$("#outputListValutes").append(
"<option value=" + $(this).find("CharCode").text() + ">" + $(this).find("CharCode").text() + "</option>");
});
};
$.ajax(requestOptions);
$("#clear").click(function() {
var sumValue = document.getElementById("sum").value = "";
var resValue = document.getElementById("result").value = "";
});
$("#convert").click(function(xml) {
//var selectCurrency = $("#inputListCurrency").val();
//findData(xml);
}(requestOptions));
function findData(xml) {
var decimalOnly = /^\s*-?[1-9]\d*(\.\d{1,2})?\s*$/;
try{
var shortName = $("#outputListCurrency").val();
var value = $("#sum").val();
if(value == "") throw new Error("Empty value");
else if(!decimalOnly.test(value)) throw new Error("value must be of decimal digits");
else if(value < 0) throw new Error("Value isn't to be below zero");
else if(isNaN(parseFloat(value))) throw new Error("Value isn't to be as symbols");
$(xml).find("Valute").each(function() {
if(shortName == $(this).find("CharCode").text()) {
var nominal = $(this).find("Nominal").text();
var course = $(this).find("Value").text();
var result = parseFloat(value) * parseFloat(nominal) / parseFloat(course);
document.getElementById("result").value = Number(result).toFixed(2);
}
});
}
catch(e) {
alert(e);
}
}
});
change the success parameter of the request to use the xmlParser function (forgot () ):
var requestOptions = {
type: "GET", //The method
url: "Course_Valute_02-07-2014.xml", //It is reference on xml file
dataType: "xml", //The type of data
crossDomain: true, //Allow to do the cross-domain request
success: xmlParser(data) //Calling function
};
I found the solution this promlem. I am happy.
var courseFilePath = "xml/Course_Currency_02-07-2014.xml";
var listCurrency = [];
function insertOptions(){
for (var i = 0; i < listCurrency.length; ++i){
$("#outputListCurrency").append(
"<option value=" + listCurrency[i] + ">" + listCurrency[i] + "</option>");
}
}
function xmlParser(xml){
$("#load").fadeOut();
$(xml).find("Valute").each(function(){
var value = $(this).find("CharCode").text();
listCurrency.push(value);
});
listCurrency.sort();
};
function findData(xml){
var decimalOnly = /^\s*-?[0-9]\d*(\.\d{1,2})?\s*$/;
try {
var shortName = $("#outputListCurrency").val();
var value = $("#sum").val();
if (value == "") throw new Error("Empty value");
else if (!decimalOnly.test(value)) throw new Error("value must be of decimal digits");
else if (value < 0) throw new Error("Value isn't to be below zero");
else if (isNaN(parseFloat(value))) throw new Error("Value isn't to be as symbols");
$(xml).find("Valute").each(function(){
if (shortName == $(this).find("CharCode").text()){
var nominal = $(this).find("Nominal").text();
var course = $(this).find("Value").text();
var result = parseFloat(value) * parseFloat(nominal) / parseFloat(course);
document.getElementById("result").value = Number(result).toFixed(2);
}
});
}
catch (e){
alert(e);
}
}
$(document).ready(function(){
$.ajax({
type: "GET", //The method of sending for data
url: courseFilePath, //It is reference on xml file
dataType: "xml", //The type of data
success: function(xml){
xmlParser(xml);
insertOptions();
}
});
//insertOptions();
$("#clear").click(function() {
document.getElementById("sum").value = "";
document.getElementById("result").value = "";
});
$("#convert").click(function() {
var selectCurrency = $("#inputListCurrency").val();
$.get(courseFilePath, findData, "xml");
});
});

WinJS Virtualized Data Source + nested asynchronous requests

Hi i'm relatively new to JavaScript and i'm working on a winjs app project where i want to use the Bing image search data source example in my project to virtualize the datasource of a listview.
My problem is understanding how the asynchronous functions work together and how to implement an async xhr request within the existing one.
Currently i'm using a synchronous request but i would like to change that into a asynchronous one.
This is my data adapter:
(function () {
var xxxDataAdapter = WinJS.Class.define(
function (devkey, query, delay) {
this._minPageSize = 2;
this._maxPageSize = 5;
this._maxCount = 50;
this._devkey = devkey;
this._query = query;
this._delay = 0;
},
{
getCount: function () {
var that = this;
var requestStr = 'http://xxx/' + that._query;
return WinJS.xhr({ url: requestStr, type: "GET", /*user: "foo", password: that._devkey,*/ }).then(
function (request) {
var obj = JSON.parse(request.responseText);
if (typeof obj.error === "undefined") {
var count = obj.length;
if (count === 0) { console.log("The search returned 0 results.", "sample", "error"); }
return count;
} else {
console.log("Error fetching results from API", "sample", "error");
return 0;
}
},
function (request) {
if (request && request.name === "Canceled") {
return WinJS.Promise.wrapError(request);
} else {
if (request.status === 401) {
console.log(request.statusText, "sample", "error");
} else {
console.log("Error fetching data from the service. " + request.responseText, "sample", "error");
}
return 0;
}
});
},
itemsFromIndex: function (requestIndex, countBefore, countAfter)
{
var that = this;
if (requestIndex >= that._maxCount) {
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
}
var fetchSize, fetchIndex;
if (countBefore > countAfter) {
//Limit the overlap
countAfter = Math.min(countAfter, 0);
//Bound the request size based on the minimum and maximum sizes
var fetchBefore = Math.max(Math.min(countBefore, that._maxPageSize - (countAfter + 1)), that._minPageSize - (countAfter + 1));
fetchSize = fetchBefore + countAfter + 1;
fetchIndex = requestIndex - fetchBefore;
} else {
countBefore = Math.min(countBefore, 10);
var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
fetchSize = countBefore + fetchAfter + 1;
fetchIndex = requestIndex - countBefore;
}
var requestStr = 'http://xxx/' + that._query;
return WinJS.xhr({ url: requestStr, type: "GET", /*user: "foo", password: that._devkey,*/ }).then(
function (request)
{
var results = [], count;
var obj = JSON.parse(request.responseText);
if (typeof obj.error === "undefined")
{
var items = obj;
for (var i = 0, itemsLength = items.length; i < itemsLength; i++)
{
var dataItem = items[i];
var req = new XMLHttpRequest();
// false = synchronous
req.open("get", "http://xxxxx/" + dataItem.id, false);
req.send();
var jobj = JSON.parse(req.response);
if (typeof jobj.error === "undefined")
{
results.push({
key: (fetchIndex + i).toString(),
data: {
title: jobj.name.normal,
date: Date.jsonFormat(dataItem.calculatedAt, "Do, MMM HH:mm Z"),
result: "",
status: "",
}
});
}
}
return {
items: results, // The array of items
offset: requestIndex - fetchIndex, // The offset into the array for the requested item
};
} else {
console.log(request.statusText, "sample", "error");
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.doesNotExist));
}
},
function (request)
{
if (request.status === 401) {
console.log(request.statusText, "sample", "error");
} else {
console.log("Error fetching data from the service. " + request.responseText, "sample", "error");
}
return WinJS.Promise.wrapError(new WinJS.ErrorFromName(WinJS.UI.FetchError.noResponse));
}
);
}
});
WinJS.Namespace.define("xxx", {
datasource: WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function (devkey, query, delay) {
this._baseDataSourceConstructor(new xxxDataAdapter(devkey, query, delay));
})
});
})();
And this is the synchronous request i would like to change to an asynchronous one:
var req = new XMLHttpRequest();
// false = synchronous
req.open("get", "http://xxxxx/" + dataItem.id, false);
req.send();
you can use then function to chain promises. In your scenario, then function need to simple have a if statement.
return WinJS.xhr(params).then(function (req)
{
if (..)
return WinJS.xhr(params2);
else
return; // then function ensures wrapping your sync result in a completed promise
}, function onerror(e)
{
// todo - error handling code e.g. showing a message box based on your app requirement
});
This is what i came up with. Map the json objects received asynchronously and make another asynchronous call for each object to get additional data. Then the nested async calls are joined and returned when all are finished.
return WinJS.xhr({ url: 'http://xxx=' + that._query }).then(function (request) {
var results = [];
var obj = JSON.parse(request.responseText);
var xhrs = obj.map(function (dataItem, index) {
return WinJS.xhr({ url: 'http://xxxx' + dataItem.attrx }).then(
function completed(nestedRequest) {
var xxJobj = JSON.parse(nestedRequest.responseText);
var dataObj = {};
dataObj.title = xxJobj.name;
dataObj.date = Date.jsonFormat(dataItem.attrtrxx, "Do, MMM HH:mm Z");
dataObj.result = "open";
dataObj.status = "foo";
if (dataItem.xx.hasOwnProperty("attrx5")) {
dataObj.opponent = dataItem.attrx4;
} else {
dataObj.opponent = dataItem.attrx3;
}
dataObj.page_title = "xXx";
dataObj.match_id = dataItem.id;
dataObj.type = "largeListIconTextItem";
dataObj.bg_image = "http://xxx/" + xxJobj.attrx2 + "-portrait.jpg";
results.push({
key: (fetchIndex + index).toString(),
data: dataObj
});
},
function (err) {
console.log(err.status);
console.log(err.responseText);
}
);
});
return WinJS.Promise.join(xhrs).then(
function (promises) {
return {
items: results, // The array of items
offset: requestIndex - fetchIndex, // The offset into the array for the requested item
};
},
function (err) {
console.log(JSON.stringify(err));
}
);
});

Categories