Add delay between ajax json calls - javascript

Sorry in advance if this isn't the proper way to ask this, please let me know how I can improve my questions :)
Essentially I have a json file which I want to pull data from (name, address, etc) in order to use a Google Maps API function to plot them as markers. This is the current ajax function I'm using:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
$(data.group).each(function(index, person) {
if (typeof person.Address != "undefined") {
geocodeAddress(geocoder, map, person);
}
});
}
});
However, this is calling the geocodeAddress function for all 800+ of my directory entries all at once, which is far above my Maps API query limit. I'd like to space these out ~100ms apart to prevent this. I tried using setInterval like to accomplish this, but it seems that the geocodeAddress line is run for all entries at once, so this would only delay all of the functions, not the length between each.
Is there another way I could pull this json data instead of using ajax, or just a way to delay each API request individually?
geocodeAddress function for reference (it both geocodes and plots markers)
function geocodeAddress(geocoder, resultsMap, person) {
//geocoding address
geocoder.geocode({'address': person.Address[0].text}, function(results, status) {
if (status === 'OK') {
//plotting coordinate as marker
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location,
icon: {
url: person.Image[0].src,
size: new google.maps.Size(120, 150),
scaledSize: new google.maps.Size(30, 38),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(15, 19)
}
});
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
}

You can loop the geocodeAddress calling with a 100ms spaced out time like below,
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
var i = 0;
var loop = function(){
if(i < data.group.length){
if (typeof data.group[i].Address != "undefined")
geocodeAddress(geocoder, map, data.group[i]);
i++;
setTimeout(loop, 100);
}
}
loop();
}
});
hope it helps.

With a little mod to your geocodeAddress function, to add an optional callback
function geocodeAddress(geocoder, resultsMap, person, callback) {
//geocoding address
geocoder.geocode({
'address': person.Address[0].text
}, function(results, status) {
if (status === 'OK') {
//plotting coordinate as marker
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location,
icon: {
url: person.Image[0].src,
size: new google.maps.Size(120, 150),
scaledSize: new google.maps.Size(30, 38),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(15, 19)
}
});
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
if (typeof callback == 'function') {
callback();
}
});
}
and, for the sake of minimal changes, adding a wrapper function for geocodeAddress that returns a Promise
function geocodeAddressPromise(geocoder, resultsMap, person) {
return new Promise(function(resolve) {
geocodeAddress(geocoder, resultsMap, person, resolve);
};
}
Your main code can be written as:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false'
}).then(function(data) {
return data.group.filter(function(person) {
return typeof person.Address != "undefined";
}).reduce(function(promise, person) {
return promise.then(function() {
return geocodeAddressPromise(geocoder, map, person);
}).then(function() {
return new Promise(function(resolve) {
setTimeout(resolve, 100);
});
});
}, Promise.resolve());
});
it uses .filter to include only persons with an address
and a fairly common .reduce pattern to chain Promises in sequence, with the addition of the 100ms timeout between resolution of one address to the start of the next geocode call

You can add delays to your array iteration using setTimeout inside an IIFE:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
//Invoke delayLoop with initial params - i = 0, delay = 100ms
(delayLoop)(0, data.group, 100, geocodePerson);
}
});
//Function to perform delayed iteration function on array elements
function delayLoop (i, list, interval, itemFunc) {
setTimeout(function() {
itemFunc(list[i]);
if (++i < list.length) {
delayLoop(i, list, interval, itemFunc);
}
}, interval)
}
//function to perform on array elements
function geocodePerson(person) {
if (typeof person.Address != "undefined") {
geocodeAddress(geocoder, map, person);
}
}

Related

Ajax POST can't read from PHP

Im writing a javascript and wanted to send the data to PHP page addProject-logic.php through ajax POST.
Although the POST request success on the javascript, but on my php page i couldnt echo, it showed undefined "latLng"
My file structure:
Structure
addMap.js :
google.maps.event.addListener(marker, 'dragend', function (marker) {
var latLng = marker.latLng
currentLatitude = latLng.lat()
currentLongitude = latLng.lng()
var latlng = {
lat: currentLatitude,
lng: currentLongitude,
}
//Post LAT LNG TO POST
function postLatLng() {
$.ajax({
type: 'POST',
url: '../includes/actions/addProject-logic.php',
data: {
latLng: latlng,
},
success: function (response) {
window.alert('Success')
},
})
}
var geocoder = new google.maps.Geocoder()
geocoder.geocode(
{
location: latlng,
},
function (results, status) {
if (status === 'OK') {
if (results[0]) {
input.value = results[0].formatted_address
map.setZoom(18)
map.panTo(latLng)
postLatLng()
} else {
window.alert('No results found')
}
} else {
window.alert('Geocoder failed due to: ' + status)
}
},
)
})
i create a function postLatLng then execute in another action
Whenever I echo on php addProject-logic.php page, echo $_POST['latLng']; it showed undefined array key latLng
Your example is a bit vague as you don't show what addProject-logic.php file does but here's a fresh example with a javascript call and a php code.
I'm simplifying by using javascript (you can convert to jQuery) and removing geocode as it seems it is not the issue here (but then, your example is vague).
I'm using fetch to make the requests in order to show the different steps. Notice the JSON.stringify call.
// Data is
var latlng = {
lat: 42,
lng: 42
}
function postLatLng() {
fetch('addProject-logic.php', {
method: 'POST',
body: JSON.stringify({
latLng: latlng
})
})
// the response sent back via php is json
.then(response => response.json())
.then(json => {
// The data returned by the php script contains latLng
window.alert(json.latLng)
})
.catch(err => {
console.error(err)
})
}
On the php side:
<?php
// Header for the JSON response
header('Content-Type: application/json; charset=UTF-8');
// parsing the post content
// My guess is you miss both this call and the JSON.stringify in the js
$data = json_decode(file_get_contents('php://input'), true);
// here we send back the post data.
echo json_encode([
'latLng' => $data["latLng"],
]);

Clear GeoJSON layer every time function is called

The function getCountryBorders() updates the map by drawing the desired country border every time the function is run. However, it just adds each country border to the current layer, rather than replacing the old border.
How can I clear the current layer each time the function is called?
const getCountryBorders = function() {
$.ajax({
url: "libs/php/getCountryBorders.php",
type: 'POST',
dataType: 'json',
success: function(result) {
const countries = result["data"]["features"];
function countryFilter(feature) {
if (feature.properties.iso_a2 === countryCode) return true
}
const borderStyle = {
"color": "red"
}
borderLayer = L.geoJson(countries, {
filter: countryFilter,
style: borderStyle
}).addTo(map);
},
error: function(jqXHR, textStatus, errorThrown) {
}
})
}
Since your borderLayer is in global scope, a very easy solution is to remove it from the map just before reassigning it:
if (borderLayer) {
borderLayer.remove();
}
borderLayer = L.geoJson(countries).addTo(map);

javascript function before google maps load

I have to put markes on google maps, but the array with lat, long is made by an Ajax request.
Map is loaded before the initialization of the array and I don't see the markers.
I think that this is the problem but I'm not so sure. hope you can help me
<script>
$(document).ready(function() {
setVariable('<?php echo $_SESSION["token"]?>');
});
</script>
<script defer
src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXX&callback=initMap">
</script>
coord = new Array();
function setVariable(token) {
format="text/plain";
$.ajax({
url: BASE_URL + "reports",
type: "GET",
contentType: "application/json; charset=utf-8",
headers: {'x-access-token': token},
cache: false,
success: function(data){
if (data.success){
$.each(data.data.reports, function (i, item) {
coord[i] = [ data.data.reports[i].lat , data.data.reports[i].lng ] ;
});
console.log(coord)
}else{
alert(data.error.message);
}
},
error: function(data){
console.log(data);
}
});
}
function initMap() {
var myLatLng = {lat: 43.1107168, lng: 12.3908279};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 2,
center: myLatLng
});
var marker, i;
for (i = 0; i < coord.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(coord[i][0], coord[i][1]),
map: map,
title: 'Hello World!'
});
}
}
How can i resolve this?
thank you very much.
You will need to restructure the code in order to make this work. We need to add markers on the map only after we have fetched the lat/long data successfully by making an AJAX request. We could do this in the following manner.
<script defer
src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXX&callback=initMap">
/*
We will keep a global variable that would contain a reference to the google map object.
It would be initialized as soon as the script for google maps is loaded and initMap function is called subsequently.
*/
var GoogleMap;
coord = new Array();
function setVariable(token) {
format="text/plain";
$.ajax({
url: BASE_URL + "reports",
type: "GET",
contentType: "application/json; charset=utf-8",
headers: {'x-access-token': token},
cache: false,
success: function(data){
if (data.success){
$.each(data.data.reports, function (i, item) {
coord[i] = [ data.data.reports[i].lat , data.data.reports[i].lng ] ;
});
console.log(coord)
var marker, i;
for (i = 0; i < coord.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(coord[i][0], coord[i][1]),
map: GoogleMap,
title: 'Hello World!'
});
}
}else{
alert(data.error.message);
}
},
error: function(data){
console.log(data);
}
});
}
function initMap() {
var myLatLng = {lat: 43.1107168, lng: 12.3908279};
GoogleMap = new google.maps.Map(document.getElementById('map'), {
zoom: 2,
center: myLatLng
});
}
Hopefully, this should work!

Getting response in network but console return error with cross origin

I'm using google map api for web...
Also I'm calling search nearby api directly from jquery to search places,
this is error in console
this is response in network
I've already added to use api from all referrer in google api console.
var param = {
key: "My_Key",
location: pos.lat+','+pos.lng,
radius: 3000,
type: "church"
};
$.ajax({
url: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?" + jQuery.param(param),
method: "GET",
async: false,
success: function(resp) {
console.log(resp);
},
error: function(error) {
console.log(error);
}
});
Don't use the Places API web service from javascript on the client, use the Google Maps Javascript API v3 Places Library.
example in documentation
proof of concept fiddle (using the posted request parameters)
code snippet:
var map;
var service;
var infowindow;
function initialize() {
var pyrmont = new google.maps.LatLng(-33.8665433, 151.1956316);
map = new google.maps.Map(document.getElementById('map'), {
center: pyrmont,
zoom: 15
});
var request = {
location: pyrmont,
radius: '3000',
type: ['church']
};
service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, callback);
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div id="map"></div>
Try adding dataType : 'jsonp' in your $.ajax call as,
$.ajax({
url: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?" + jQuery.param(param),
method: "GET",
dataType : 'jsonp',
async: false,
success: function(resp) {
console.log(resp);
},
error: function(error) {
console.log(error);
}
});
Hope this helps!

Uncaught exception when calling Google maps directionsService

I am getting an Uncaught InvalidValueError: in property origin: not a string; and not a LatLng or LatLngLiteral: not an Object error when I call the Google maps directions service - even so, the directions seem to be added to the map?
Here is the function that calls the directions service between the current location (currentPos) and a location not too far away (LatLng(52.705151, -2.741861))
function calcRoute() {
var start = currentPos;
var end = new google.maps.LatLng(52.705151, -2.741861);
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
Here is the code that initializes the map and calls the calcRoute() function:
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var currentPos;
var destinationPos;
var map;
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom: 14
};
map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
directionsDisplay.setMap(map);
var infoWindow = new google.maps.InfoWindow();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
currentPos = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var marker = new google.maps.Marker({
position: currentPos,
map: map,
title: "You are here"
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')
map.setCenter(currentPos);
$.ajax({
type: 'GET',
url: $('#AddMarkersToMap').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
addMarkers(data, infoWindow);
},
error: function () {
alert("Error");
}
});
}, function () {
handleNoGeolocation(true);
});
} else {
handleNoGeolocation(false);
}
calcRoute();
}
Some Googling suggested the exception might be caused because the map hadn't loaded so I tried putting the calcRoute call like this which didn't help:
$(function () {
calcRoute()
});
Your currentPos variable is undefined when you call calcRoute.
getCurrentPosition is asynchronous and will not have executed before calcRoute and therefore not set currentPos.
If you need to use currentPos in calcRoute you should call it in the callback to getCurrentPosition to ensure that it is defined.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
currentPos = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var marker = new google.maps.Marker({
position: currentPos,
map: map,
title: "You are here"
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')
map.setCenter(currentPos);
$.ajax({
type: 'GET',
url: $('#AddMarkersToMap').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
addMarkers(data, infoWindow);
},
error: function () {
alert("Error");
}
});
calcRoute();
//\\//\\//\\
}, function () {
handleNoGeolocation(true);
});

Categories