I want to set global variable from function and loop ajax to get distance.
However the nearestIndex variable is always undefined.
First solution I got was to use async: false - this is work in my pc browser, but this project is webservice to android, and this solution not work to webview.
And of course async: false not recommended. I need this example in my case, I've been looking for this problem in stack overflow, but i always failed to understand about callback.
var allDestination = ["A", "B", "C"];
var nearestIndex;
function getNearest(){
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var tempDistance;
for(var i=0; i<allDestination.length; i++){
var destination = allDestination[i].getLatLng().lat + "," + allDestination[i].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function (data) {
var distance = data.distance;
if(i == 0){
tempDistance = distance;
nearestIndex = i;
} else {
if(distance < tempDistance){
tempDistance = distance;
nearestIndex = i;
}
}
}
});
}
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
getNearest();
allDestination[nearestIndex].addTo(map);
}
As you are dealing with Async call; your relevant code has to get called from success handler of ajax call as follows:
var allDestination = ["A", "B", "C"];
var nearestIndex;
var tempDistance;
var successReceived = 0; //counter to keep watch on ajax success callback
//modify the function signature to receive index as well as callback function
function getNearest(index, callbackFunction) {
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var destination = allDestination[index].getLatLng().lat + "," + allDestination[index].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function(data) {
successReceived++; //increment the success counter
var distance = data.distance;
if (index == 0) {
tempDistance = distance;
nearestIndex = index;
} else {
if (distance < tempDistance) {
tempDistance = distance;
nearestIndex = index;
}
}
//check if we got all the ajax response back. If yes then call the callback function
if(successReceived == allDestination.length && typeof callbackFunction == 'function')
{
callbackFunction();
}
}
});
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
for (var i = 0; i < allDestination.length; i++) {
//pass the current index and callback function
getNearest(i,function(){
allDestination[nearestIndex].addTo(map);
});
}
}
I ever have got the same problem like you,
it because asincrounous function cant return anything.
so I think you shoud inject allDestination[nearstIndex].addTo(map); into ajax success
if(i == 0){
tempDistance = distance;
allDestination[i].addTo(map);
} else {
if(distance < tempDistance){
tempDistance = distance;
allDestination[i].addTo(map);
}
}
or you create function to handle ajax success,,, CMIIW
Related
I have 2 functions that fetch data via the jQuery AJAX method.
Both look identical save for the URL. Both requests are successful and show the data in console, but only one returns the data through the parent function.
saveLoc fetches data that says "OK", and the "OK" is returned if printed to console in the parent code.
getLoc fetches data that is a number, say "17". The number is printed to console from within the function, but in the parent code, the variable (savedLoc) simply returns undefined
Any advice? Am I missing something?
function saveLoc(story,chapter,loc) {
jQuery.ajax({
type: "GET",
url: "index.php?action=saveloc&story="+story+"&chapter="+chapter+"&loc="+loc,
data: "",
cache: false,
success: function (data2) {
console.log("Location saved: "+loc);
return data2;
}
});
}
function getLoc(story,chapter) {
jQuery.ajax({
type: "GET",
url: "index.php?action=getloc&story="+story+"&chapter="+chapter,
data: "",
cache: false,
success: function (data) {
console.log("Location retrieved: "+data);
return data;
}
});
}
$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (results==null){
return null;
}
else{
return decodeURI(results[1]) || 0;
}
}
var story = $.urlParam('story');
var chapter = $.urlParam('chapter');
$(document).ready(function(){
var start = 1;
var savedLoc = getLoc(story,chapter);
console.log("savedLoc: "+savedLoc);
if(savedLoc > 0) {
var d = $(document).height(),
c = $(window).height();
var scrollPos = Math.floor((savedLoc / 100) * (d - c));
window.scrollTo(0, scrollPos);
}
setTimeout(function() {
$(window).on('scroll', function(){
console.log("scroll detected");
setTimeout(function() {
var s = $(window).scrollTop(),
d = $(document).height(),
c = $(window).height();
var scrollPercent = (s / d) * 100;
saveLoc(story,chapter,scrollPercent);
},3000);
});
},6000)
});
The ajax getLoc is a asynchronous task, so your savedLoc = getLoc(); will not get the return value of it's success function.
For managin asynchronous tasks, like ajax, there are some solutions:
Original and Simple way: If you want to get the return value of ajax, you should use a global variable, and transfer a callback into the ajax function, like getLoc, then call the callback in success;
Promise, manage the asynchronous tasks with synchronous way, refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise;
manage the asynchronous tasks with synchronous way provided in ES6, refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
async await, a replacement for generator, refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
and for more information, refer to the blog, https://blog.risingstack.com/asynchronous-javascript/
function saveLoc(story,chapter,loc) {
jQuery.ajax({
type: "GET",
url: "index.php?action=saveloc&story="+story+"&chapter="+chapter+"&loc="+loc,
data: "",
cache: false,
success: function (data2) {
console.log("Location saved: "+loc);
return data2;
}
});
}
function getLoc(story,chapter, callback) {
jQuery.ajax({
type: "GET",
url: "index.php?action=getloc&story="+story+"&chapter="+chapter,
data: "",
cache: false,
success: function (data) {
console.log("Location retrieved: "+data);
savedLoc = data;
callback && callback();
}
});
}
$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (results==null){
return null;
}
else{
return decodeURI(results[1]) || 0;
}
}
var savedLoc;
var story = $.urlParam('story');
var chapter = $.urlParam('chapter');
$(document).ready(function(){
var start = 1;
getLoc(story,chapter, afterLocCallback);
function afterLocCallback() {
console.log("savedLoc: "+savedLoc);
if(savedLoc > 0) {
var d = $(document).height(),
c = $(window).height();
var scrollPos = Math.floor((savedLoc / 100) * (d - c));
window.scrollTo(0, scrollPos);
}
setTimeout(function() {
$(window).on('scroll', function(){
console.log("scroll detected");
setTimeout(function() {
var s = $(window).scrollTop(),
d = $(document).height(),
c = $(window).height();
var scrollPercent = (s / d) * 100;
saveLoc(story,chapter,scrollPercent);
},3000);
});
},6000)
}
});
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
Firstly, getLoc is not returning anything. so put a return statement in there.
secondly, $.ajax returns jqXHR object. You can use then, done, fail methods on this object. If you are not familiar with these read about promise concepts.
Once your async call is successful do the rest of the operations inside the then method.
function saveLoc(story,chapter,loc) {
//return the ajax promise here
return jQuery.ajax({
type: "GET",
url: "index.php?action=saveloc&story="+story+"&chapter="+chapter+"&loc="+loc,
data: "",
cache: false,
success: function (data2) {
console.log("Location saved: "+loc);
return data2;
}
});
}
function getLoc(story,chapter) {
//return the ajax promise here
return jQuery.ajax({
type: "GET",
url: "index.php?action=getloc&story="+story+"&chapter="+chapter,
data: "",
cache: false,
success: function (data) {
console.log("Location retrieved: "+data);
return data;
}
});
}
$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (results==null){
return null;
}
else{
return decodeURI(results[1]) || 0;
}
}
var story = $.urlParam('story');
var chapter = $.urlParam('chapter');
$(document).ready(function(){
var start = 1;
getLoc(story,chapter).then(function(data){
var savedLoc = data;
console.log("savedLoc: "+savedLoc);
if(savedLoc > 0) {
var d = $(document).height(),
c = $(window).height();
var scrollPos = Math.floor((savedLoc / 100) * (d - c));
window.scrollTo(0, scrollPos);
}
setTimeout(function() {
$(window).on('scroll', function(){
console.log("scroll detected");
setTimeout(function() {
var s = $(window).scrollTop(),
d = $(document).height(),
c = $(window).height();
var scrollPercent = (s / d) * 100;
// I think you are not using the return value of this call. So not using any promise then here.
saveLoc(story,chapter,scrollPercent);
},3000);
});
},6000)
});
});
I am stuck in a situation where I am hitting multiple ajax calls on controller while working in debugger mode everything works fine but in normal mode it showing argument out of range exception
for (var i = 0; i < artdata.length; i++) {
addNewStepMultiple(artdata[i], i)
}
function addNewStepMultiple(artifactData, index) {
if (artifactData != null) {
var tcIndex, data, url;
var suiteId = serviceFactory.getComponentInfo().id;
var gridInstance = $("#Suite_Grid").data("kendoGrid");
if (gridInstance._data.length == 0) {
tcIndex = -1 + index + 1;
} else {
tcIndex = $("#Suite_Grid").data("kendoGrid").select().index();
if (tcIndex == -1) {
tcIndex = tcIndex + index;
} else {
tcIndex = tcIndex + index + 1;
}
}
console.log('tcIndex' + tcIndex);
var newTcIndex = tcIndex;
var treeBinding = JSON.stringify(artifactData);
url = "/Suite/AddNewStep";
data = { SuiteID: suiteId, position: tcIndex, artifactModel: treeBinding };
$.ajax({
type: "POST",
url: url,
data: data,
success: function (res) {
debugger; //$scope.SuiteData.data(res);
bindSuiteGrid(res); //$scope.SuiteData.data(result)
$scope.setChanges();
//var tr = grid.element.find('tbody tr:eq(' + (newindex) + ')'); //.addClass('k-state-selected')
// grid.select(tr);
var tr = $('#Suite_Grid table tr:eq(' + (res.length) + ')')
$("#Suite_Grid").data("kendoGrid").select(tr);
loadingStop("#vertical-splitter", ".btnTestLoader");
},
error: function (error) {
debugger
loadingStop("#vertical-splitter", ".btnTestLoader");
serviceFactory.showError($scope, error);
}
});
}
}
Please let me know how to solve the problem.
in your scenario loop can not wait up to your ajax request in normal mode. so click here to know the how to make a multiple ajax calls
i want to check whether is a valid item or not before saving the values. then i create java-script function to check validation and return result. but the problem is this function returns before validate items, the always true the condition above if condition. my code is below. could anyone help me please?
this is series of ajax call and i'm not aware of how to use callback for this..
if(IsValidItems() != ''){
//Do something
}
function IsValidItems() {
var IsvalidStatus = '';
var lineqty = 0;
var LineNumber = -1;
var allRowData = jQuery("#tblJQGrid").jqGrid("getRowData");
for (var i = 0; i < allRowData.length - 1; i++) {
if (allRowData[i].BulkItem != "False") {
if (allRowData[i].quantity != '') {
lineqty = parseInt(allRowData[i].quantity);
LineNumber = i + 1;
var postURL = "/BookingDetail/GetItemAvailablity?ItemCode=" + allRowData[i].itemCode + "&StartDate=" + allRowData[i].StartDate + "&EndDate=" + allRowData[i].EndDate + "&srno=" + allRowData[i].srno + "&locationID=" + allRowData[i].Location;
$.ajax({
url: postURL,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: "",
type: "POST",
async: true,
dataFilter: function (data) {
return data;
},
success: function (result) {
if (lineqty > parseInt(result)) {
IsvalidStatus = IsvalidStatus + "," + LineNumber;
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) { }
});
}
}
}
return IsvalidStatus;
}
I have a program which calls a function in javascript with 1 o more requests to 1 servlet, I want to execute request after request and get the response after each exucution, to make this I have 1 function, but it only shows the result after all requests have been executed.
function cmd(args) {
width = 0;
var res = args.split('\n');
var largo = res.length;
var progressLength = 100 / largo;
for (var i = 0; i < largo; i++)
{
if (res[i] == 'desconectar')
{
desconectar();
break;
}
else
{
executeCMD(res[i]);
}
}
}
function executeCMD(args)
{
$.ajax({
type: "POST",
url: 'Controlador',
data: {cmd: args, operacion: 1},
success: function (response) {
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response;
},
dataType: 'text',
async: false
});
}
If I add window.alert(response); inside success field it shows the progress step by step and works fine, but it show alerts which I don't want.
This is I want http://imgur.com/a/9nclR but I'm getting only last picture.
The solution if anyone is intersting was using a recursive function as next:
function cmd(args) {
width = 0;
move(0);
var res = args.split('\n');
var largo = res.length;
var valInit = 0;
if (largo > valInit)
{
executeCMD(res, valInit);
}
}
function executeCMD(args, i)
{
$(document).ready(function () {
$.ajax({
type: "POST",
url: 'ControladorServlet',
data: {cmd: args[i], operacion: 1, ticket: ticket, iddispositivo: sesion},
success: function (response) {
var textarea = document.getElementById('respuesta');
var res = response.trim().split('\n');
if(error){//dc}
else
{
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response.trim() + "\n\n";
var valor = (100) * (i + 1) / args.length;
move(valor);
if (i + 1 < args.length)
{
executeCMD(args, i + 1);
}
}
},
dataType: 'text'
});
});
}
So I have a loop, which performs an ajax call on each iteration and I want to set the progress bar updated.. But it is not updating, it goes to 100% directly when ending...
I've tried to put the bar update call outside the success action (inside the loop directly) but it isn't working either..
$('button.page').on('click', function(e){
var $userList = textArray($('#page-userlist').val().replace('http://lop/', '').split(/\n/));
var $proxyList = textArray($('#page-proxylist').val().replace('http://', '').split(/\n/));
var $question = $('#page-question').val();
var data = {
question: $question,
users: $userList,
proxies: $proxyList
};
var i = 0, p = 0, max = data.proxies.length, totalusers = data.users.length, percent = 0;
$('#log').append("\n" + moment().calendar() + "\n");
var progressbar = $('#page-progress');
$.each(data.users, function(k, u){
if(typeof(p) !== 'undefined' && p !== null && p > 0)
{
if(i % 10 == 0 && i > 1) p++;
if(p == max) return false;
}
var proxy = data.proxies[p];
percent = Math.round((i / totalusers) * 100);
$.ajax({
type: "POST",
url: Routing.generate('viral_admin_bot_page'),
data: {question: $question, user: u, proxy: proxy},
success: function(result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
},
error: function(error) {
$('#log').append(error);
}
});
i++;
});
});
If i do console.log(percent); it is updating perfectly on each iteration, so I don't know where can be the problem.
Here is my code (without the ajax call because it isn't the problem) http://jsfiddle.net/dvo1dm03/20/
it will output to console the percentage, the objetive is to update the bar to the percentage completed in each loop, so it goes in "realtime" with loop.
Ok, here's how to do it asynchrounously.
var speed = 75;
var number_of_calls_returned = 0; // add number_of_calls_returned++ in your ajax success function
var number_of_total_calls;
var loaded = false;
function processUserData(){
if( number_of_calls_returned < number_of_total_calls){
setTimeout(function(){processUserData();}, 200);
}
else{
//received all data
// set progressbar to 100% width
loaded = true;
$("#page-progress").animate({width: "100%"},500);
$("#page-proxylist").val("Received data");
}
}
function updateProgress(percent, obj){
setTimeout(function(x){
if(!loaded)
$(obj).width(x + "%");
}, percent*speed, percent);
}
$('button.page').on('click', function (e) {
var $userList = textArray($('#page-userlist').val().replace('http://lop/', '').split(/\n/));
var $proxyList = textArray($('#page-proxylist').val().replace('http://', '').split(/\n/));
var $question = $('#page-question').val();
var data = {
question: $question,
users: $userList,
proxies: $proxyList
};
var i = 0,
p = 0,
max = data.proxies.length,
totalusers = data.users.length,
percent = 0;
//$('#log').append("\n" + moment().calendar() + "\n");
var progressbar = $('#page-progress');
number_of_total_calls = totalusers;
$.each(data.users, function (k, u) {
if (typeof (p) !== 'undefined' && p !== null && p > 0) {
if (i % 10 == 0 && i > 1) p++;
if (p == max) return false;
}
var proxy = data.proxies[p];
percent = (i / totalusers) * 100; //much smoother if not int
updateProgress(percent, progressbar);
i++;
// simulate ajax call
setTimeout(function(){number_of_calls_returned++;}, Math.random()*2000);
});
//callback function
setTimeout(function(){processUserData();}, 200);
});
var textArray = function (lines) {
var texts = []
for (var i = 0; i < lines.length; i++) {
// only push this line if it contains a non whitespace character.
if (/\S/.test(lines[i])) {
texts.push($.trim(lines[i]));
}
}
return texts;
}
Check it out here! jsFiddle (really cool!)
Your problem is cause by the fact that you have a closure for your success function and every success function shares the same percent variable. You can fix it like this:
success: function(percent, result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
}.bind(percent),
Where you'll need to shim bind in older browsers, or like this, which is a little uglier, but should work everywhere without a shim:
success: (function(percent) { return function(result) {
$('#log').append("\nAtacado usuario " + u + " con proxy: " + proxy + "\n");
$(progressbar).width(percent + "%");
}; }( percent ),
if what you want is to increase the update bar with each success of AJAX calls I'd suggest an easier solution (I've simplified the js code for clarity's sake):
$('button').click(function (e) {
var i = 0,
cont = 0,
totalusers = 100,
percent = 0;
var progressbar = $('#page-progress');
for (; i < totalusers; i++) {
$.ajax({
type: "POST",
url: '/echo/json/',
data: {
question: 'something',
user: 1,
proxy: 2
},
success: function (result) {
cont += 1;
percent = Math.round((cont / totalusers) * 100);
progressbar.width(percent + "%");
},
error: function (error) {
$('#log').append(error);
}
});
};
});
You can see it in action in this fiddle.
Hope this helps or at least give you some ideas.
Update the progress bar using setTimeout method.
it will wait for some time and then update the width of progressbar.
myVar = setTimeout("javascript function",milliseconds);
Thanks,
Ganesh Shirsat
I would like to make a recommendation of trying to make a self contained example that doesn't rely on the post so that it is easier for you or us to solve the problem
As well, you can console log elements so you could try logging the progressbar element, percent and the response of the ajax request
(This code is to replace the javascript sections of the fiddler)
var i = 0;
moveProgress();
function moveProgress(){
if(i < 10000)
{
setTimeout(function(){
$('#page-progress').width((i / 1000) * 100);
moveProgress();
},2);
i++;
}
}
The reason that it wasn't working was because the loop ran so fast that it was loaded by the time the script loaded it, the timeout allows you to delay the execution a bit(Though not necessarily recommended to use because of potential threading issues.