I have a simple series of functions :
convertXML();
function convertXML(){
var xmlObj = xmlToJson(xml.responseXML)
.query.results.WMS_Capabilities;
console.log("convertXML");
(function checkReturn(){
if(typeof xmlObj != 'undefined'){
return (function(){ return createData(xmlObj)})();
}
else {
setTimeout(checkReturn, 50);
}
})();
}
function createData(xmlObj){
for (var i = 0; i < xmlObj.Capability.Layer.Layer.length; i++){
var row={};
row = xmlObj.Capability.Layer.Layer[i];
WMSLayers.push(row);
};
console.log("createdata",WMSLayers)
return (function(){return finish()})();
}
function finish(){
console.log(n == Server.length-1)
if (n == Server.length-1){
//n is defined as an argument
//this code is a part of a bigger function
//same for Server variable
createTable();
};
}
The problem is that that the convertXML function sometimes returns the callback function createData with the xmlObj variable undefined. So I have to check if the variable is defined to call the callback function.
My question is isn't a function suppose to return when all its variables are finished loading data?
UPDATE
This is how I make the request:
var req = {
"type" :"GET",
"dataType":"XML",
"data" : null,
"url" : url
};
//make the request (ajax.js)
ajax(req,ajaxSuccess,ajaxError);
function ajax(prop,onsuccess,onerror){
// data = data || null;
// var url = "wps"; // the script where you handle the form input.
$.ajax({
type: prop.type,
dataType: prop.dataType,
data: prop.data,
url: prop.url,
success: function (data, textStatus, xhr) {
console.log(xhr)
onsuccess(xhr);
},
error:function (data ,textStatus, xhr) {
onerror(xhr);
}
});
// e.preventDefault();
}
function ajaxSuccess(xhr){
$("#messages").append(
'<span style="color:blue">' +
getFullTime() +
'</span> Response HTTP status <b>' +
xhr.status +
' [' + xhr.statusText + ']' +
'</b> from:' +
' <a style="color:grey;text-decoration:none;" href="' +
url+
'" target="_blank">'+
Server[i].link +
Request["getCapabilities"]+
'</a><br>'
);
//create the wms
createWMS(xhr, Server[i],i);//this is where the convertXML,createData and finish functions are located
};
You can use the complete function of $.get(). Note, n does not appear to be defined within finish function.
function convertXML(xml, textStatus, jqxhr) {
var xmlObj = xmlToJson(jqxhr.responseXML)
.query.results.WMS_Capabilities;
console.log("convertXML");
if (typeof xmlObj != 'undefined') {
createData(xmlObj);
}
}
function createData(xmlObj){
for (var i = 0; i < xmlObj.Capability.Layer.Layer.length; i++){
var row = xmlObj.Capability.Layer.Layer[i];
WMSLayers.push(row);
};
console.log("createdata",WMSLayers)
finish();
}
$.get("/path/to/resource", convertXML, "xml")
.fail(function(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
});
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 a strange issue with my method :
$('#search').on('keyup', function () {
var valNow = $('#search').val();
if (last !== valNow && valNow !== '') {
console.log(valNow + ' / ' + i);
//interrogate a server from a cities
$.get(path + '/' + strategy() + '/' + valNow,
function (data, status) {
//here
console.log(status);
if (status === 'success') {
cities = [];
cities = data;
}
},
'json');
// make new last
last = valNow;
//list result
var items = [];
console.log(cities[0]);
console.log(' / ' + i);
$(cities).each(function (index, value) {
console.log(value);
var notStrong = valNow.length;
var strong = value.length;
items.push('<li><strong>'+ valNow +'</strong>'+value.substr(notStrong)+'</li>');
});
$('.result').append(items).show();
i++;
console.log('finished');
}
}
);
the problem is simply when I use (/bind) this function I get finish message before console.log(status) (commented://here), the $.get function takes a lot of times to interrogate the web service , I don't know why I have this issue with $.get function, is it a thread or something like this ??? what I want is to get in order all statements (console.log(status) then console.log('finish')).
Try appending your options inside the function block which gives you the data
$('#search').on('keyup', function () {
var valNow = $('#search').val();
if (last !== valNow && valNow !== '') {
console.log(valNow + ' / ' + i);
//interrogate a server from a cities
$.get(path + '/' + strategy() + '/' + valNow,
function (data, status) {
if (status === 'success') {
cities = data;
// append all the options here
}
},'json');
}
}
);
Using AJAX to get data from a remote location always runs asynchronous, meaning that, when calling $.get, the call to the server will be made and the js code returns immediately. Then, after the code in between, console.log('finish') will be called, and some time later, when the $.get call receives the response from the server, the code inside the $.get anonymous function will be called, which then runs console.log(status).
That is the intended design for grabbing data from remote locations. If you want to run the other code strictly after that, you have to run it inside the callback function of $.get, like that:
$('#search').on('keyup', function() {
var valNow = $('#search').val();
if (last !== valNow && valNow !== '') {
console.log(valNow + ' / ' + i);
//interrogate a server from a cities
$.get(path + '/' + strategy() + '/' + valNow,
function(data, status) {
//here
console.log(status);
if (status === 'success') {
cities = [];
cities = data;
}
// make new last
last = valNow;
//list result
var items = [];
console.log(cities[0]);
console.log(' / ' + i);
$(cities).each(function(index, value) {
console.log(value);
var notStrong = valNow.length;
var strong = value.length;
items.push('<li><strong>' + valNow + '</strong>' + value.substr(notStrong) + '</li>');
});
$('.result').append(items).show();
i++;
console.log('finished');
},
'json');
}
});
There are other ways to make the code more pretty, for example using Promises.
I have a javascript function which is load help menu list (dropdown).
First function: GetPageKeyword()
function GetPageKeyword() {
var url = window.location.href.replace(window.location.origin, '').replace('/#', '').replace('#', '').replace('//', '/');
url = url.split("?")[0];
url = GetURL(url);
if (url.lastIndexOf('/') == (url.length - 1))
url = url.slice(0, -1);
if (url.indexOf('/') == 0)
url = url.substring(1, url.length);
$.ajax({
url: "/api/PageKeywords/GetLabelsByUrl",
type: 'Get',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
cache: false,
data: { url: url },
success: function (data) {
var res = data.data;
var htmlAppend = '<a id="hlpMenuLink" class="dropdown-toggle" data-toggle="dropdown"><i style="font-size: 17px;" class="fa fa-question-circle"></i></a>';
if (res.length > 0) {
$.getJSON("https://test.com/search.json?label_names=" + res[0].labels,
function (data) {
if (data.results.length > 0) {
htmlAppend += '<ul id="menuHelpUl" class="dropdown-menu pull-right">';
for (var i = 0; i < data.results.length; i++) {
htmlAppend += "<li>" + data.results[i].name + "</li>";
}
htmlAppend += "</ul>";
}
$('#helpMenu').html(htmlAppend);
});
}
$('#helpMenu').html(htmlAppend);
setTimeout(function () { GetArticulateDetails(); }, 1100);
},
error: function (jqXhr, textStatus, errorThrown) {
var err = jqXhr;
}
});
}
But now I need to add more item to help menu.
In the second function I tried to add the new item to ul id="menuHelpUl" which I build in the first function.
Second function: GetArticulateDetails()
function GetArticulateDetails() {
var url = window.location.href.replace(window.location.origin, '').replace('/#', '').replace('#', '').replace('//', '/');
url = url.split("?")[0];
url = GetURL(url);
if (url.lastIndexOf('/') == (url.length - 1))
url = url.slice(0, -1);
if (url.indexOf('/') == 0)
url = url.substring(1, url.length);
$.ajax({
url: "/api/PageKeywords/GetArticulateLabelByUrl",
type: 'Get',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
cache: false,
data: { url: url },
success: function (data) {
var res = data.data;
var htmlAppend = '<hr/>';
if (res.length > 0) {
for (var i = 0; i < res.length; i++) {
htmlAppend += "<li>" + res[i].name + "</li>";
}
}
$('#menuHelpUl').append(htmlAppend);
},
error: function (jqXhr, textStatus, errorThrown) {
var err = jqXhr;
console.log(err);
}
});
}
In first function GetPageKeyword at last on success response, i am calling the second function which is
setTimeout(function () { GetArticulateDetails(); }, 1100);
Here I am having problem some case the second function is not working because it may be it can not find id of #helpMenu.
code : function : GetArticulateDetails :-- $('#helpMenu').html(htmlAppend);
So there how I call my second funtion after compleate first function.
Try to call your second function right in the end of your ajax success callback:
$.ajax({
/* settings */
success: function (data) {
var res = data.data;
var htmlAppend = '<a id="hlpMenuLink" class="dropdown-toggle" data-toggle="dropdown"><i style="font-size: 17px;" class="fa fa-question-circle"></i></a>';
if (res.length > 0) {
$.getJSON("https://test.com/search.json?label_names=" + res[0].labels,
function (data) {
if (data.results.length > 0) {
htmlAppend += '<ul id="menuHelpUl" class="dropdown-menu pull-right">';
for (var i = 0; i < data.results.length; i++) {
htmlAppend += "<li>" + data.results[i].name + "</li>";
}
htmlAppend += "</ul>";
}
$('#helpMenu').html(htmlAppend);
GetArticulateDetails(); // here !
});
}
$('#helpMenu').html(htmlAppend);
}
});
Also, maybe it would be necessary to protect this call by
if (data.results.length > 0) {
GetArticulateDetails();
}
declare the menuHelpUl as a ui element like this:
var menuHelpUl = $('<ul id="menuHelpUl" class="dropdown-menu pull-right">');
and append li elements to it in loop
var li = $("<li>" + data.results[i].name + "</li>");
menuHelpUl .append(li);
now pass the menuHelpUl to GetArticulateDetails in ajax success:
GetArticulateDetails(menuHelpUl);
and use it in ajax success
menuHelpUl.append(htmlAppend);
In your first method the call
$('#helpMenu').html(htmlAppend)
Should be inside the handler for getJson(...)
Currently it is called before that method completes but relies on data generated by that async callback.
(I'd give you an explicit code change but difficult to edit on mobile)
Edit - actually the above line is duplicated. The one outside the handler can be removed. Perhaps there are duplicate Ids?
You can also call the second method from within the getJson handler after the Html has been updated.
menuHelpUl will only exist if the call in getJson returns some data. If it does not, there will be no element.
Try this solution using promises in javascript:
function GetPageKeyword() {
return new Promise((resolve, reject)=>{
//your code here
resolve();
});
}
function GetArticulateDetails() {
return new Promise((resolve, reject)=>{
//your code here
resolve();
});
}
Call it like this:
GetPageKeyword().then((result)=>{
GetArticulateDetails();
}).catch((error)=>{
//handle error
});
here is the edited first function :
function GetPageKeyword() {
return new Promise((resolve,reject)=>{
var url = window.location.href.replace(window.location.origin, '').replace('/#', '').replace('#', '').replace('//', '/');
url = url.split("?")[0];
url = GetURL(url);
if (url.lastIndexOf('/') == (url.length - 1))
url = url.slice(0, -1);
if (url.indexOf('/') == 0)
url = url.substring(1, url.length);
$.ajax({
url: "/api/PageKeywords/GetLabelsByUrl",
type: 'Get',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
cache: false,
data: { url: url },
success: function (data) {
var res = data.data;
var htmlAppend = '<a id="hlpMenuLink" class="dropdown-toggle" data-toggle="dropdown"><i style="font-size: 17px;" class="fa fa-question-circle"></i></a>';
if (res.length > 0) {
$.getJSON("https://test.com/search.json?label_names=" + res[0].labels,
function (data) {
if (data.results.length > 0) {
htmlAppend += '<ul id="menuHelpUl" class="dropdown-menu pull-right">';
for (var i = 0; i < data.results.length; i++) {
htmlAppend += "<li>" + data.results[i].name + "</li>";
}
htmlAppend += "</ul>";
$('#helpMenu').html(htmlAppend);
resolve()
}else{
$('#helpMenu').html(htmlAppend);
resolve()
}
});
}else{
$('#helpMenu').html(htmlAppend);
resolve()
}
},
error: function (jqXhr, textStatus, errorThrown) {
var err = jqXhr;
reject()
}
});
})
}
You can use jquery.when
$.when(GetPageKeyword()).then(GetArticulateDetails());
from the code it seems like $('#helpMenu') is found to be null or undefined.
try to check the null or undefind status of $('#helpMenu')
**if($('#helpMenu') == null || $('#helpMenu') == undefined)**
and then perform the append html operation.
I am not sure if this is due to the fact that getJSON is asynchronous or not. I think that would be the most obvious reason, but I don't have a clear understanding of how that works. In my js file, I call the healthCheck method on the body element. Nothing happens. Is my getJSON callback function even getting called? I don't know.
I have uploaded the script on JSFiddle.
The code is also below:
var baseURL = "http://someURL";
var id = "00000001";
var key = "0000aaaa-aa00-00a0-a00a-0000000a0000";
var healthcheck = "/version/healthcheck?";
( function($) {
$.fn.healthCheck = function() {
var timestamp = new Date().toJSON().toString();
var request = healthcheck + "timestamp=" + timestamp + "&devid=" + id;
var signature = CryptoJS.HmacSHA1(request, key);
request = baseURL + request + "&signature=" + signature;
$.getJSON(request, function(data) {
var result = new Object();
$.each(data, function(key, val) {
result.key = val;
if (val == false) {
this.innerHTML = "PTV API is currently not working. Error type: " + key + ".";
} else {
this.append(key + " working. <br />");
}
});
});
return this;
};
}(jQuery));
Many thanks in advance. I hope my query is well placed. If anyone knows some good resources to get a better understanding of asynchronous methods in jQuery that would be greatly appreciated, also. I haven't found many that have been easy to follow yet.
Try 1) setting context of jQuery.ajax( url [, settings ] ) to this of $.fn.healthCheck ; 2) create reference to this object at $.each()
var baseURL = "http://someURL";
var id = "00000001";
var key = "0000aaaa-aa00-00a0-a00a-0000000a0000";
var healthcheck = "/version/healthcheck?";
(function($) {
$.fn.healthCheck = function() {
// set `this` object within `$.getJSON`
var timestamp = new Date().toJSON().toString();
var request = healthcheck + "timestamp=" + timestamp + "&devid=" + id;
var signature = CryptoJS.HmacSHA1(request, key);
request = baseURL + request + "&signature=" + signature;
$.ajax({
url:request
, type:"GET"
, contentType: false
, context: this
, processData:false
}).then(function(data) {
// reference to `this` within `$.each()`
var that = this;
var result = new Object();
$.each(JSON.parse(data), function(key, val) {
result.key = val;
if (val == false) {
// `that` : `this`
that.innerHTML = "PTV API is currently not working. Error type: " + key + ".";
} else {
that.append(key + " working. <br />");
console.log("complete"); // notification
}
});
}, function(jqxhr, textStatus, errorThrown) {
console.log(textStatus, errorThrown); // log errors
});
return this;
};
}(jQuery));
$("body").healthCheck();
See also How do I return the response from an asynchronous call?
var baseURL = "https://gist.githubusercontent.com/guest271314/23e61e522a14d45a35e1/raw/62775b7420f8df6b3d83244270d26495e40a1e9d/a.json";
var id = "00000001";
var key = "0000aaaa-aa00-00a0-a00a-0000000a0000";
var healthcheck = "/version/healthcheck?";
(function($) {
$.fn.healthCheck = function() {
var timestamp = new Date().toJSON().toString();
var request = healthcheck + "timestamp=" + timestamp + "&devid=" + id;
var signature = 123;// CryptoJS.HmacSHA1(request, key);
request = baseURL + request + "&signature=" + signature;
$.ajax({
url:request
, type:"GET"
, contentType: false
, context: this
, processData:false
}).then(function(data) {
var that = this;
var result = new Object();
$.each(JSON.parse(data), function(key, val) {
result.key = val;
if (val == false) {
that.innerHTML = "PTV API is currently not working. Error type: " + key + ".";
} else {
that.append(key + " working. <br />");
console.log("complete"); // notification
}
});
}, function(jqxhr, textStatus, errorThrown) {
console.log(textStatus, errorThrown); // log errors
});
return this;
};
}(jQuery));
$("body").healthCheck()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
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);
}
})();