I've been playing around with JavaScript and there's something I don't quite understand. I have this piece of code here:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
});
}
});
Ok, now suppose the for loop runs 3 times. If we uncomment the first "console.log(datas)" line and run the page, in the console we see 3 "datas" objects with their own "id" and "area". If I comment that first "console.log(datas)" and uncomment the second "console.log(datas)" in the geocode callback, when I run the code, all 3 "datas" objects are exactly the same in terms of "id", "area", and "latlng". Whereas I expected the 3 "datas" objects would be different with their own latlngs.
Any ideas?
When is the function you pass to the geocoder.geocode function run? If it's not being run immediately then the for loop will run through all three times before the geocode function is run. That means that datas['id'] and datas['area'] will have been set to the last iteration of the loop... in which case you need to capture the datas array inside a closure for the geocode function.
In which case you'd need something like:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(datas){ return function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
}}(datas));
}
});
This prevents the datas variable as used by the anonymous function being updated by the for loop.
I think this is a scope problem. By the time that last console.log runs the p variable will already refer to the last obj. You need to capture p in a new scope.
for( var p in obj.List ) {
(function(p) {
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
geocoder.geocode( { 'address': datas['area'] }, function(results,status) {
...
});
}(p));
}
I think datas has to be declared as a global array? Has it?
Related
I struggle passing this into my function as demonstrated below:
console.log('geolocation is ' + this.isGeolocating);
let geocoder = new google.maps.Geocoder;
geocoder.geocode({'location': geolocation}, function(results, status, self = this) {
console.log('geolocation is ' + self.isGeolocating);
if (status === 'OK') {
if (results[0]) {
console.log(results[0]);
self.geolocated = 'success';
} else {
// No results found
self.geolocated = 'error';
}
} else {
console.log('Geocoder failed due to: ' + status);
self.geolocated = 'error';
}
});
this.isGeolocating = false;
this is properly accessible before and after the function, but how can I pass it through? self in my case is undefined as well.
There's typically three approaches. One is to assign this to another variable, conventionally named self or that, before the function; the variable will be captured into the function's closure.
let that = this;
geocoder.geocode(..., function(...) {
that.isGeolocating
});
Another is to explicitly tell the function what this should be, using bind:
geocoder.geocode(..., function(...) {
this.isGeolocating
}.bind(this));
The third one is to use a rocket function, which does not reassign this:
geocoder.geocode(..., (...) => {
this.isGeolocating
});
Try this:
let myBeautifulThis = this;
let geocoder = new google.maps.Geocoder;
geocoder.geocode({'location': geolocation}, function(results, status) {
console.log('geolocation is ' + myBeautifulThis.isGeolocating);
});
You need to either store a reference to this in a variable outside of your function, or use arrow functions.
So either
let self = this;
geocoder.geocode({'location': geolocation}, function(results, status) {
// you existing code here
// use self.isGeolocating
});
of just
geocoder.geocode({'location': geolocation}, (results, status) => {
// using this in here will use the this of the outer scope.
// use this.isGeolocating
});
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 years ago.
$(function() {
var lat = 41.9100711;
var lng = 12.535`enter code here`9979;
var geocoder = new google.maps.Geocoder();
var address = "<?php echo $citta ?>";
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK)
{
// do something with the geocoded result
//
lat = results[0].geometry.location.lat();
lng = results[0].geometry.location.lng();
}
});
alert("latitudine"+lat);
I need lat and lng for this plugin and i need to declare lat and lng inside this, for this is why i'm asking about to have a globa variablse to use .... in case any other idea to find lat and lng from an address to use with this plugin ?
$('#map-container').storeLocator({'deafultlat'=lat,'defaultlng'=lng});
The variables are changed but your alert code is outside your jQuery function:
$(function(){ /* your code */ })
alert(lat + "/" + lng);
Since you are using var inside a function, they aren't globals anymore. What you want to do is, remove the var statements in the $() function and instead write it like this:
var lat, lng;
$(function(){
// your current code.
})
// no alert here since lat/lng are empty when alert is called.
Be aware of JavaScript concurrency, your alert code will most likely execute before the $() method. That's because $() is a shorthand for $("document").ready() which will delay the call until, well, the document is ready.
Try to put your alert into the call back of geocoder to solve this.
Right below where you set lat/lng:
$(function() {
var lat = 41.9100711;
var lng = 12.5359979;
var geocoder = new google.maps.Geocoder();
var address = "";
geocoder.geocode({
'address': address
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// do something with the geocoded result //
lat = results[0].geometry.location.lat();
lng = results[0].geometry.location.lng();
alert("latitudine"+lat); // works!
}
});
});
To make lat/lng real globals you could write something like this:
window.lat = 0.0;
window.lng = 0.0;
// Now whenever you change window.lat, it's applied to all functions since window is already a global.
Or just use var outside any function to make globals.
Imo it's bad practice to use globals, you should use instead a callback whenever you need these lat/lngs.
I have an object which contains an array that I then pass to another function in order for that function to use. The only thing is, when I go to access these variables, console.log says they are undefined. It's strange as when I log the whole array it ways the values are there but when I go to access the array element specifically, it returns undefined.
Here is my code:
googleMapsFunctions.prototype.calculateDistances = function() {
var that = this;
console.log(that.latLngArray);
var closeClubs = [];
var sortable = [];
var resultsArray = [];
jQuery(this.clubs).each(function(key, club) {
var clubLatLng = new google.maps.LatLng(club.latitude, club.longitude);
var distanceFromLoc = clubLatLng.distanceFrom(that, "", "");
//alert(distanceFromLoc);
//that.clubs[key].distance = distanceFromLoc;
//closeClubs.push(club);
});
closeClubs.sort(function(a, b) {
return a.distance - b.distance;
});
}
googleMapsFunctions.prototype.setLatLng = function() {
var that = this;
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
that.latLngArray.push(parseFloat(results[0].geometry.location.lat()));
that.latLngArray.push(parseFloat(results[0].geometry.location.lng()));
}
});
}
//Client Code
var googleMapsClass = new googleMapsFunctions(JSONItems, searchTerm);
googleMapsClass.setLatLng();
googleMapsClass.calculateDistances();
I am using console.log to print out the array (that.latLngArray) which gives the following:
I then click on the aray brackets and it takes me to the following (which is the correct information).
I just can't seem to access these variables and it says that they are undefined.
Can anyone see what is happening here?
Thanks
Simplest thing to do would be to just move the distance calculation inside the callback:
googleMapsFunctions.prototype.setLatLng = function() {
var that = this;
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
that.latLngArray.push(parseFloat(results[0].geometry.location.lat()));
that.latLngArray.push(parseFloat(results[0].geometry.location.lng()));
// now it's safe to check the distances
that.calculateDistances();
}
});
}
This question already has an answer here:
How to get a javascript lat/lng variable out of a Google Map API function
(1 answer)
Closed 9 years ago.
I've been searching here all day for help with what is likely, just a basic noob javascript mistake.
I'm trying to get the lat/long from an address using google's geocoder glass. However, I can't seem to assign it to a global or even derive it from the object's property (which I would prefer). Basically all I need at this point to to just get the location from the geocoder and everything else should fall in place. See code:
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=true&libraries=places"></script>
<script>
var geocoder = new google.maps.Geocoder();
var ListingAddress = '1600 Pennsylvania Ave NW Washington, DC 20500';
var map;
var infowindow;
//var ListingLoc = new google.maps.LatLng(-33.8665433, 151.1956316);
var ListingLatLong;
var ListingLoc;
function initialize() {
geocoder.geocode({
address: ListingAddress
},
function(results){
ListingLatLong = results[0].geometry.location;
ListingLoc = new google.maps.LatLng(ListingLatLong);
});
map = new google.maps.Map(document.getElementById('map_canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: ListingLoc,
zoom: 15
});
var request = {
location: ListingLoc,
radius: 500,
types: ['school']
};
infowindow = new google.maps.InfoWindow();
var 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++) {
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);
</script>
AND the markup
<div id="map_canvas" style="width:600px;height:400px;border:none;"></div>
The second argument of geocoder.geocode is a callback function that executes asynchronously. That means that the function will run sometime after the rest of your code. Thus,ListingLatLong is not assigned a value until after you've tried to use it.
Asynchronous execution is the norm for performing network requests in JavaScript. Instead of causing your code to hang by waiting a long time for a network round-trip, you simply dispatch a request and define a listener function to fire when the request completes some time later. That's what is happening here: the function argument to geocoder.geocode is a listener function that fires once the data arrives from Google's geocoding server. geocoder.geocode doesn't run that function, exactly -- it just says, "Okay, JavaScript, here's a function you should run whenever my request completes."
To solve this problem, simply move any code that needs to use the values of results (and/or ListingLatLong) inside the callback function:
geocoder.geocode({
address: ListingAddress
},
function(results){
ListingLatLong = results[0].geometry.location;
ListingLoc = new google.maps.LatLng(ListingLatLong);
// ** note this is inside the callback now **
map = new google.maps.Map(document.getElementById('map_canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: ListingLoc,
zoom: 15
});
// add the rest of your code here, too
// ...
});
(Side note: you should use uppercase variable names only for constructors (e.g., var Person = function(name) { this.name = name; }) and lowercase variable names for instances (e.g., someGuy = new Person("Bob");). When I see the name ListingLatLong, I expect it to be a constructor, but it's not, so I'd suggest using listingLatLong instead.)
I've read similar posts, but still didn't find a solution for myself. Basically I have an array with countries+towns in PHP and I need to show them on the map with markers. Here is my code:
function showAddress(markers) {
var address = "<?php echo $Fcity[$j], " , ", $Fcountry[$j]?>";
if (geocoder) {
geocoder.getLatLng(address, function(point) {
if (!point) {
alert(address + " not found");
} else {
var marker = new GMarker(point);
map.addOverlay(marker);
markers[i] = marker;
marker.openInfoWindowHtml(address);
}
}
);
}
}
Everything seems to work if I geocode one location, but I can't put it into a loop to process all of them.
for (var i = 0; i < markers.length; i++) {
showAddress(markers[i]);
}
In your showAddress function, you reference markers[i].
However, you don't pass in i... that variable is not in the scope of the function. So, you aren't iterating and adding, you are adding variables over and over to a non-existent place in the array.
You either need to pass in i or not encapsulate showAddress in a function.
How about making the function showAddresses and putting the loop in the function.