JavaScript code seems to skip callback to another function - javascript

I am writing functions in my JavaScript file to output an address. It is not the cleanest, but it worked before my current issue came up. I am trying to callback and get an address but when I log the address to the console, it is undefined. I'm not sure what I am doing wrong.
function calculateDistance(vnames, vlocations) {
// PROGRAM NEVER GOES THROUGH THIS???
clientLoc((address) => {
var origin = address;
alert("Address: " + address);
});
// PROGRAM NEVER GOES THROUGH THIS???
console.log("my location is: " + origin);
var venueNames = vnames,
venueLocs = vlocations,
service = new google.maps.DistanceMatrixService();
// 5. Output band name and distance
// Matrix settings
service.getDistanceMatrix(
{
origins: [origin],
destinations: venueLocs,
travelMode: google.maps.TravelMode.DRIVING, // Calculating driving distance
unitSystem: google.maps.UnitSystem.IMPERIAL, // Calculate distance in mi, not km
avoidHighways: false,
avoidTolls: false
},
callback
);
// Place the values into the appropriate id tags
function callback(response, status) {
// console.log(response.rows[0].elements)
// dist2 = document.getElementById("distance-result-2"),
// dist3 = document.getElementById("distance-result-3");
for(var i = 1; i < response.rows[0].elements.length + 1; i++) {
var name = document.getElementById("venue-result-" + i.toString()),
dist = document.getElementById("distance-result-" + i.toString());
// In the case of a success, assign new values to each id
if(status=="OK") {
// dist1.value = response.rows[0].elements[0].distance.text;
name.innerHTML = venueNames[i-1];
dist.innerHTML = response.rows[0].elements[i-1].distance.text;
} else {
alert("Error: " + status);
}
}
}
}
This is the function I am using the callback from:
// Find the location of the client
function clientLoc (callback) {
// Initialize variables
var lat, lng, location
// Check for Geolocation support
if (navigator.geolocation) {
console.log('Geolocation is supported!');
// Use geolocation to find the current location of the client
navigator.geolocation.getCurrentPosition(function(position) {
console.log(position);
lat = position.coords.latitude;
lng = position.coords.longitude;
// Client location coordinates (latitude and then longitude)
location = position.coords.latitude + ', ' + position.coords.longitude
// console.log(location)
// Use Axios to find the address of the coordinates
axios.get('https://maps.googleapis.com/maps/api/geocode/json?key=AIzaSyAg3DjzKVlvSvdrpm1_SU0c4c4R017OIOg', {
params: {
address: location,
key: 'AIzaSyBH6yQDUxoNA3eV81mTYREQkxPIWeZ83_w'
}
})
.then(function(response) {
// Log full response
console.log(response);
var address = response.data.results[0].formatted_address;
// Return the address
console.log(address);
//return clientLoc.address;
// CALLBACK
callback(address);
})
});
}
else {
console.log('Geolocation is not supported for this Browser/OS version yet.');
return null;
}
}

a function that has a callback doesn't block execution, so your function clientLoc gets called and presumably if that code works, the origin variable will get set and your alert call will fire ... BUT the code below clientLoc is not waiting for the clientLoc call to finish ... it proceeds through the rest of the function ... granted i'm not too familiar with the es6 syntax but the concept is the same. You probably want to move the console.log("my location is: " + origin); and any code that reiles on the origin variable being set inside the callback, to make it cleaner use some promises

Related

How to I get distance "value" from google maps distance matrix api?

I am autofilling an input field with the below which gives me distance.text value which is expressed in km but I'd like to get the distance.value for precision distance.
function getdistance(address){
var dest_address = address; // Address enter by user
var origin_address = document.getElementById('hall').value ; // Address where you need to calculate distance.
var distanceService = new google.maps.DistanceMatrixService(); // store Google Distance Service method
// Call distance matrix services.
// default parameters
distanceService.getDistanceMatrix({
origins: [dest_address],
destinations: [origin_address],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
durationInTraffic: true,
avoidHighways: false,
avoidTolls: false
},
function (response, status) {
// check status from google service call
if (status !== google.maps.DistanceMatrixStatus.OK) {
console.log('Error:', status);
} else {
// Response contain JSON.
var error = response.rows[0].elements[0].status;
$('#error').html(error);
var distance = response.rows[0].elements[0].distance.value;
document.getElementById("distance").value = distance;
}
});
}
I tried changing
var distance = response.rows[0].elements[0].distance.text;
to
var distance = response.rows[0].elements[0].distance.value;
but still only getting the "text" value.
Please help
Actually, Sorry! changing the line to...
var distance = response.rows[0].elements[0].distance.value;
...works. I just needed to clear my cache for the .js file change to kick in. =/ =/ =/

How to return the coordinates of a getLocation function, return latitude and longitude

I am attempting to build a weather API using the freeCodeCamp API for the weather project.
What I want to do is use the getLocation function to get the latitude and longitude and then return them as a variables that I can use to then concat to a URL.
By using the URL I can obtain the json information I need to output the Fahrenheit and any other info I need.
Since I require an https connection I am using codepen for testing purposes.
additional info:
Codepen:
https://codepen.io/rogercodes/pen/gXvOoO
freeCodeCamp API:
https://fcc-weather-api.glitch.me/
HTML
<html>
<head>
<!-- <link rel="stylesheet" type="text/css"
href="css/quoteStyles.css"> -->
</head>
<body>
<button onclick="getWeather(finalLat,finalLon)">getWeather</button>
<p>What is</p>
<button onclick="getLocation()">Try It</button>
<p id='geoAPI'>Geo API</p>
<p id="lan">Test Lan: </p>
<p id='geo'>geoLocal</p><script>
</script>
</body>
<script src="javascript/weatherTest.js"></script>
<!-- <script src="JSON/weather.json"></script> -->
Javascript
var api= "https://fcc-weather-api.glitch.me/api/current?";
var googleApi="https://www.googleapis.com/geolocation/v1/geolocate?
key=AIzaSyCOMzDSyP4RkXwp7mSiFiuAZroyrazU5eM";
var lat, lon;
var x= document.getElementById("geoLocal");
var tempX= document.getElementById("temp");
var geoLocal=document.getElementById("geo");
var xLat= document.getElementById("lat");
// Following functions will get the latitude and longitude
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
geoLocal.innerHTML = "Geolocation is not supported by this
browser.";
}
}
var finalLat=finalCoords[0];
var finalLon=finalCoords[1];
function showPosition(position){
geoLocal.innerHTML="Latitude:" + position.coords.latitude +
"<br> Longitude: " + position.coords.longitude;
lat= position.coords.latitude;
lon=position.coords.longitude;
var finalCoords=[lat,lon]
return finalCoords;
}
showPosition(position);
console.log(api,lon);
xLat.innerHTML="testLat: " + finalCoords[0];
finalLat=finalCoords[0];
finalLon=finalCoords[1];
function getWeather(finalLat,finalLon){
var completeApi=api+lon+"&"+lat;
// lon="lon="+ position.coords.longitude;
// lat='lat='+ position.coords.latitude;
xLat.innerHTML="testLatitude: " +completeApi;
return completeApi;
}
getWeather(finalLat,finalLon);
The commented information below is the additional work I am going to be using to complete outputting the weather for any user location.
// var completeApi="getWeather(lat,lon)";
// JSON request for API to get temperature
// var ourRequest= new XMLHttpRequest();
// ourRequest.open('GET',completeApi);
// ourRequest.onload= function() {
// if (ourRequest.status>= 200 && ourRequest.status<400){
// var ourData= JSON.parse(ourRequest.responseText);
// renderHTML(ourData);
// console.log("ourData",ourData);
// } else{
// console.log("Connection Error, Please try again.")
// }
// };
// ourRequest.send();
// console.log(ourRequest)
// var jsonWeather= JSON.stringify(ourData);
// document.body.innerHTML=jsonWeather;
// function renderHTML(data){
// var htmlString="";
// for (i=0;i<data.lenth;i++){
// htmlString=data[i].coord;
// console.log(data[i].coord)
// tempX.textContent= data;
// }
// // htmlString.textContent=data[0];
// tempX.textContent= data;
// // return data;
// }
// console.log(ourRequest)
// var geoLocation= document.getElementById("geoAPI");
// geoLocation.innerHTML=completeApi;
The geolocation API is an asynchronous operation. It would be best to implement this usecase using Promises (if available ) or the callback pattern.
Basically the following asynchronous operations need to happen in order:
Get the current location using geolocation API
Get the weather data using an AJAX request
Make whatever DOM updates necessary to show the results
Sample Implementation using the callback pattern:
// Helper to get the location from the browser
function getLocation(cb) {
cb = (cb && typeof cb === 'function' && cb) || function() {};
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(pos) {
cb(null, [pos.coords.latitude, pos.coords.longitude]);
});
} else {
cb(new Error('Browser does not support geolocation'));
}
}
// Helper to make the AJAX call to the API
function getWeather(coords, cb) {
cb = (cb && typeof cb === 'function' && cb) || function() {};
// Build URL
var url = 'https://fcc-weather-api.glitch.me/api/current?lat=' + coords[0] + '&lon=' + coords[1];
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
// TODO: Handle error cases
if (this.readyState == 4 && this.status == 200) {
// TODO: Handle possible parse exception
cb(null, JSON.parse(xhttp.responseText));
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
// This gets triggered on clicking the button
function handleClick() {
//1. Get the current location using geolocation API
getLocation(function(err, coords) {
if (err) {
// Handle error, return early
return;
}
// 2. Get the weather data using an AJAX request
getWeather(coords, function(err, data) {
if (err) {
// Handle error, return early
return;
}
// Data is available here. Update DOM/process as needed
// 3. Make whatever DOM updates necessary to show the results
console.log(data);
});
});
}
<button onclick="handleClick()">Get Weather Data</button>

Google API Geocoding OVER_QUERY_LIMIT , 5 addresses per second?

First of all, I didn't reach the maximum daily limit of 2,500 addresses.
I have 25 addresses, and I already set the sleep time in JavaScript between each address to 5 seconds. I always get OVER_QUERY_LIMIT error after 18 or 19 addresses are geocoded. The rest 7 or 6 address always not get geocoded.
Google API Geocoding as limit of 5 addresses per second, or they have increased?
Thanks.
Code
function geocodeAddress(geocoder, addresses ) {
var arrayLength = addresses.length;
for (var i = 0; i < arrayLength; i++) {
var address = String(addresses[i]);
// alert(address)
sleep(5000)
geocoder.geocode({'address': address}, function (results, status)
{
if (status === google.maps.GeocoderStatus.OK) {
var result = results[0].geometry.location;
var name = results[0].formatted_address;
writeFile(geocode_file_path, name + ',' + result.toString());
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
This is a complex problem. Async is very tricky to get your head around.
Having said that, here's a solution that would work. I would prefer a Promise based solution but Promises are another issue that takes time to understand.
function geocodeAddresses(geocoder, addresses, callback){
var result = [];
// this internal function does the hard work
function geocode(address) {
// get timestamp so we can use it to throttle later
var lastCall = Date.now();
// call google function asynchronously
geocoder.geocode({'address': address}, function (results, status) {
// process the return data here
if (status === google.maps.GeocoderStatus.OK) {
result.push({
location: results[0].geometry.location,
address: results[0].formatted_address
});
} else {
result.push({ error: status });
}
// check to see if there are any more addresses to geocode
if (addresses.length) {
// calculate when next call can be made. 200ms is 5 req / second
var throttleTime = 200 - (lastCall - Date.now());
setTimeout(function(){ // create timeout to run in 'throttletime` ms
// call this function with next address
geocode(addresses.shift());
}, throttleTime);
} else { // all done return result
callback(result);
}
});
}
// start the process - geocode will call itself for any remaining addresses
geocode(addresses.shift());
}
Since this function is asynchronous, you have to use it asynchronously ... hence the callback. So you use it as follows:
geocodeAddresses(geocoder, addresses, function(result){
// do what you need with the result here
console.log(result);
});
This is about as simple as I can make it. I've created a jsbin that mocks out the geocoder call and shows real results. Change the throttleTime to bigger numbers to see it slow down.
I hope this helps.

Trying to get local weather

I am trying to get local weather by getting currentposition and passing it to url for getting results. I can't seem to be able to pass the coordinates outside the getCurrentPosition.
My codepen is: http://codepen.io/rush86999/pen/MKMywE
if (navigator.geolocation) {
//position.coords.longitude
var app = {
getGeoLoc: function(id) {
var self = this;
navigator.geolocation.getCurrentPosition(function(position) {
var myVar1, myVar2, myVar3; // Define has many variables as you want here
// From here you can pass the position, as well as any other arguments
// you might need.
self.foundLoc(position, self, myVar1, myVar2, myVar3);
}, this.noloc, {
timeout: 3
});
},
foundLoc: function(position, self, myVar1, myVar2, myVar3) {
this.latituide = position.coords.latituide;
this.longitude = position.coords.longitude;
console.log('#4 position coords work in foundLoc: ', this.latitude, this.longitude);
},
latitude: '',
longitude: ''
};
console.log('#5 found loc in app, ', app.foundLoc);
var url = 'api.openweathermap.org/data/2.5/weather?lat=' + app.latitude + '&lon=' + app.longitude + '&APPID=7bda183adf213c8cfa2ef68635588ef3';
//lets look inside url
console.log('#1 url has coordinates: ', url);
Theres a few issues here.
Firstly, you don't seem to be calling the getGeoLoc method, so that would be the first fix.
You have included an error callback of this.noloc but it isn't included in your object.
There are a few typo's for your co-ordinates
You are making your API request before the geolocation has resolved so app.latitude and app.longitude will be undefined. This should ideally be wrapped in a method that gets called upon a successful geolocation request.
var app = {
getGeoLoc : function (id) {
//Removed timeout option due to error
var options = {}; //{ timeout: 3 };
navigator.geolocation.getCurrentPosition(this.foundLoc.bind(this), this.noloc, options);
},
foundLoc : function(position) {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
console.log('coords ', this.latitude, this.longitude);
// Call your get weather function
// Using call to bind the context of `this`
this.getWather.call(this);
},
// Error method
noloc: function(err) {
console.log(err.message);
},
// Method to get your weather after location is found
getWather: function() {
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=' + this.latitude + '&lon=' + this.longitude +'&APPID=7bda183adf213c8cfa2ef68635588ef3';
console.log('URL is: '+url);
$.getJSON(url, function(data) {
console.log('Your weather data', data);
// Do your dom stuff here
});
},
latitude: '',
longitude: ''
};
// Make sure to call your initialising function
app.getGeoLoc();
NOTE: I have removed the HTML stuff for the demo and have removed the timeout option as it caused an error.
Link to forked codepen

Geolocation can't return confirmation?

I'm looking for a way to trigger user geolocation navigator function from another function mapInit(). It nearly works, but I can't have a proper callback of getCurrentPosition() to confirm it went well.. it return undefined each times.
My geolocation object will have to achieve other tasks so I don't want it to trigger mapInit(). It should have to get user location, record it and return trueor false.. Any guess?
Thanks :)
// Get user current position, return true or false
//
var geolocation = {
get: function() {
if (alert(navigator.geolocation.getCurrentPosition(this.success, this.error, {
enableHighAccuracy: true,
maximumAge: 5000
})) {
return true;
} else {
return false;
}
},
success: function(position) {
this.last = position; // record last position
return true;
},
error: function() {
alert('code: ' + error.code + 'n' + 'message: ' + error.message + 'n')
return false;
},
last: undefined,
}
// Initialize leaflet map and get user location if coords are undefined
//
var mapInit = function(latitude, longitude) {
if (!latitude && !longitude) { // if no latlng is specified, try to get user coords
if (geolocation.get()) {
latitude = geolocation.last.coords.latitude;
longitude = geolocation.last.coords.longitude;
} else {
alert('oups!');
}
}
var map = L.map('map').setView([latitude, longitude], 15);
L.tileLayer('http://{s}.tile.cloudmade.com/#APIKEY#/68183/256/{z}/{x}/{y}.png', {
minZoom: 13,
maxZoom: 16,
}).addTo(map);
var marker = L.marker([latitude, longitude]).addTo(map);
}
Not sure I understand what you're trying to do but when you call "getCurrentPosition" the first argument you pass is a method that will be called with the Position once it is retrieved. As you said in your comment getCurrentPosition will always return immediately but the callback method will be called if the user position can be retrieved (it may never be called):
navigator.geolocation.getCurrentPosition( function(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
//do something like recent the Map
});
You will need to create the Leaflet Map first with some default coordinates and then recenter the map with the coordinates provided to the callback method.

Categories