I am trying to get lat and long info from Google Geocoder, but although the information is properly extracted on the call that is being done, for some reason the js variable gets empty imediately after getting to my second alert on this piece of code (the one outside "if" condition):
var map, marker, latLong;
var geocoderlat = new google.maps.Geocoder();
var addresslat = '<?php echo str_replace(" ","+",$address);?>';
function initMap() {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLong = results[0].geometry.location;
alert("Inside IF: "+latLong);
} else {
latLong = '<?php echo $latitude.",".$longitude;?>';
}
})
alert("Outside: "+latLong);
var isDraggable = !('ontouchstart' in document.documentElement);
var mapOptions = {
center: new google.maps.LatLng(latLong),
zoom: 12,
(...)
Obviously there's a lot of code besides this part, but the rest of the code doesn't matter in this case because this variable is never again used anywhere in my code (I even searched with Agent Ransack all over the files so be sure that this variable was not being used anywhere else).
EDIT:
Ok, this is really, really weird...
function getGeoLatLong(addresslat) {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
return results[0].geometry.location;
} else {
return '<?php echo $latitude.",".$longitude;?>';
}
})
}
alert("Outside function: "+getGeoLatLong(addresslat));
This still returns "undefined" in the alert.
geocoderlat.geocode is taking more time to execute while the code execution has already reached your second alert. you need to use setTimeout to check the results or try this.
function initMap() {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLong = results[0].geometry.location;
alert("Inside IF: "+latLong);
alert("Outside: "+latLong);
var isDraggable = !('ontouchstart' in document.documentElement);
var mapOptions = {
center: new google.maps.LatLng(latLong),
zoom: 12,
(...)
} else {
latLong = '<?php echo $latitude.",".$longitude;?>';
}
})
Also, if you want to use latLong = '<?php echo $latitude.",".$longitude;?>'; as the default latLong you need to declare it at the top. then it will be anyways overridden when geocode finishes loading
EDIT
Try this.
function getGeoLatLong(addresslat) {
geocoderlat.geocode( { 'address': addresslat}, checkresults)
}
function checkresults(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
alert("Outside function: " + results[0].geometry.location);
//declare the big chunk of code as a function and make a call to it.
} else {
alert("Outside function: <?php echo $latitude.','.$longitude;?>");
//declare the big chunk of code as a function and make a call to it.
}
}
getGeoLatLong(addresslat);
Related
I am working on a google maps API project.
I take lat and long values from a database and display them in HTML rendered by PHP.
I want to draw a route on map when I click the button with the lat&long values. ( check the image http://imgur.com/DkxlFbC )
But there is something going wrong and always taking the same values to draw the route.
I try to use changehandler but does not work.
index.php:
<?php
$test=mysql_query("SELECT lat, lng FROM markers ");
?>
<div class='container'>
<div class='row'>
<center>
<?php
while ($deneme=mysql_fetch_assoc($test)) {
extract($deneme);
echo '<br>';
echo '<h6 id="lat" class="box-design">'.$deneme['lat'].'</h6>';
echo '<h6 id="lng" class="box-design">'.$deneme['lng'].'</h6>';
echo '<br>';
echo '<input id="submit" onclick="myFunction()" type="submit" class="btn btn-primary" value="Button">';
echo '</div>';
}
?>
</center>
</div>
</div>
JS:
function myFunction() {
infoWindow = new google.maps.InfoWindow;
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer({ polylineOptions:{strokeColor:"#4a4a4a",strokeWeight:5}, suppressMarkers:true });
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
infoWindow.setPosition(pos);
infoWindow.setContent('Location found.');
infoWindow.open(map);
map.setCenter(pos);
directionsDisplay.setMap(map);
destLatLng = new google.maps.LatLng(document.getElementById('lat').textContent, document.getElementById('lng').textContent);
directionsService.route({
origin: pos,
destination: destLatLng,
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
}, function() {
handleLocationError(true, infoWindow, map.getCenter());
});
} else {
handleLocationError(false, infoWindow, map.getCenter());
}
}
Like was mentioned in comments, the id attribute needs to be unique.
The id global attribute defines a unique identifier (ID) which must be unique in the whole document. 1
Use a technique like the one below to add a numeric index to each set of latitude and longitude values with associated buttons. Notice the last reference (i.e. onclick="myFunction('.$index++.')") uses the post-increment operator to increase the index for the next iteration of the while loop.
$index = 1;
while ($deneme=mysql_fetch_assoc($test)) {
extract($deneme);
echo '<br>';
echo '<h6 id="lat'.$index.'" class="box-design">'.$deneme['lat'].'</h6>';
echo '<h6 id="lng'.$index.'" class="box-design">'.$deneme['lng'].'</h6>';
echo '<br>';
echo '<input id="submit" onclick="myFunction('.$index++.')" type="submit" class="btn btn-primary" value="Button">';
echo '</div>';
}
Then since the javascript function myFunction() will now be passed an integer , that argument (e.g. named index) can be used to find the associated latitude and logitude values (or those could be used as arguments to in the function call instead).
So update the function definition to include that argument:
function myFunction() {
becomes:
function myFunction(index) {
and then this line:
destLatLng = new google.maps.LatLng(document.getElementById('lat').textContent, document.getElementById('lng').textContent);
can be updated to use that index:
destLatLng = new google.maps.LatLng(document.getElementById('lat' + index).textContent, document.getElementById('lng' + index).textContent);
Also, to re-use the same directions service and directions renderer, declare those at the start of the javascript, and then initialize them in the function that initializes the map (e.g. initMap()):
var map, pointA, directionsService, directionsDisplay;
function initMap() {
var options = {};
/*
code to setup options
*/
map = new google.maps.Map(document.getElementById('map-canvas'), options);
directionsService = new google.maps.DirectionsService;
directionsDisplay = new google.maps.DirectionsRenderer({ /* ... */});
}
That way the code in myFunction() can just directionsService.route() and directionsDisplay.setDirections() when appropriate.
Putting all of this together, we have something like demonstrated in this phpfiddle.
1https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id
i am trying to get a walkscore from the walkscore API.
i make the ajax request to my php file, i get the response but i kee getting "Unexpected end of JSON input" when i try to alert the walkscore.
This is the PHP (if i test it directly through the URL, it gives me a perfectly json formatted result)
<?
function getWalkScore($lat, $lon, $address) {
$address=urlencode($address);
$url = "http://api.walkscore.com/score?format=json&address=$address";
$url .= "&lat=$lat&lon=$lon&wsapikey=KEY";
$str = #file_get_contents($url);
return $str;
}
$lat = $_GET['lat'];
$lon = $_GET['lon'];
$address = stripslashes($_GET['address']);
$json = getWalkScore($lat,$lon,$address);
echo $json;
?>
and this is my ajax call:
function loadStats() {
var geocoder = new google.maps.Geocoder;
var latlngStr = $("#loadStats").attr("data-latlng").split(',', 2);
var latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};
var reverseAddress='';
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[1]) {
map.setZoom(11);
/*** Getting address needed for Walkability API call ***/
reverseAddress = results[1].formatted_address;
//alert (parseFloat(latlngStr[0]));
//alert(parseFloat(latlngStr[1]));
//alert(reverseAddress);
$.ajax({
type:"GET",
url:"scripts/walkscore.php",
data: {"address" : reverseAddress ,
"lat" : parseFloat(latlngStr[0]),
"lng" : parseFloat(latlngStr[1])
},
success: function(response){
var obj = $.parseJSON(response);
alert(obj.walkscore);
}
});
} else {
alert('No results found');
}
} else {
alert('Geocoder failed due to: ' + status);
}
});
//var Lat=$("#loadStats").attr("data-latlng").slice(0, $("#loadStats").attr("data-latlng").indexOf(",")) ;
//var Lng=$("#loadStats").attr("data-latlng").slice($("#loadStats").attr("data-latlng").indexOf(",")+1,$("#loadStats").attr("data-latlng").lenght) ;
}
I don't know what i am doing wrong. this is the JSON i get from the API
{ "status": 1 , "walkscore": 4 , "description": "Car-Dependent" , "updated": "2016-04-04 21:15:44.699150" , "logo_url": "https://cdn.walk.sc/images/api-logo.png" , "more_info_icon": "https://cdn.walk.sc/images/api-more-info.gif" , "more_info_link": "https://www.redfin.com/how-walk-score-works" , "ws_link": "https://www.walkscore.com/score/Acres-homes-Houston-TX-USA/lat=29.852555/lng=-95.447845/?utm_source=cinquedomande.com&utm_medium=ws_api&utm_campaign=ws_api" , "help_link": "https://www.redfin.com/how-walk-score-works" , "snapped_lat": 29.8530 , "snapped_lon": -95.4480 }
I figured it out.
I was stupid enough to pass lng instead of lon to the php script.
I want users to do the following:
1) Enter their Street Address and Zip Code and hit "Submit", which will trigger Google Maps to geocode the address and place a marker on the map. I'm using the below code for this (which is working fine and getting me all the address info I need):
var geocoder;
var map;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(37.7789, -122.3917);
var mapOptions = {
center: latlng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
}
function codeAddress() {
var address = document.getElementById('streetAddress').value +", "+document.getElementById('zipCode').value;
geocoder.geocode( { 'address': address, 'region': 'US'}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0].address_components) {
for (var i in results[0].address_components) {
if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "street_number") {
var streetNumber= results[0].address_components[i].long_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "route") {
var streetName= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "neighborhood") {
var neighborhood= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "administrative_area_level_1") {
var state= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "postal_code") {
var zipCode= results[0].address_components[i].long_name;
}
}
}
console.log(streetNumber+", "+streetName+", "+neighborhood+", "+state+", "+zipCode);
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
2) After the user sees the marker, I want them to hit a "Confirm" button to submit this data to my server (I'm using Firebase via their Javascript API). The question I have is how do I best store the variables 'streetNumber', 'streetName', 'city', 'state', 'zipCode', and 'neighborhood' between the time that Google Maps returns the data and when the user hits "Confirm" button? The only thing I can think of is storing it on the browser window (e.g. window.streetName, window.streetNumber, etc), but I know that's not best practice.
You may e.g. store these data as properties of the button, it will be very easy to access them later(but it's also not a good practice).
The best thing you can do is to store all your objects in a single "class" (with all I mean everything that is global, currently also map, geocoder, codeAddress and initialize are global )
Here a sample code(ready to use, it doesn't expose any global property):
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false">
</script>
<script type="text/javascript">
//a self-executing, anonymous function
(function(opts,ns){
//"that" is our object, it holds all properties and methods
//and is only visible within the scope of this function
var that = {geocoder: null,
map: null,
opts: opts,
ns: ns,
postData: null},
goo = google.maps,
byId = function(id){return document.getElementById(id);};
//initialize the map
that.initialize=function() {
var latlng = new goo.LatLng(this.opts.lat,this.opts.lng);
var mapOptions = {
center: latlng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new goo.Map(byId(this.opts.ids.map), mapOptions);
//assign click-handlers to the buttons
goo.event.addDomListener(byId(this.opts.ids.btnGeo),'click',function(){
that.codeAddress.call(that);});
goo.event.addDomListener(byId(this.opts.ids.btnSend),'click',function(){
that.onSubmit.call(that);});
}
//send the data here
that.onSubmit=function(){
alert(JSON.stringify(that.postData));
}
//parse the address-components into an object
that.parseAddressComponents=function(ac){
var components={
street_number: ['streetNumber', 'long_name'],
route: ['streetName', 'short_name'],
administrative_area_level_1:['state', 'short_name'],
neighborhood: ['neighborhood', 'short_name'],
postal_code: ['zipCode', 'long_name']
},o={};
for(var i=0;i<ac.length;++i){
inner:for(var c in components){
if(ac[i].types[0]==c){
o[components[c][0]]=ac[i][components[c][1]];
break inner;
}
}
}
return o;
}
//geocoding-callback
that.geoCallback=function(results, status){
if (status == goo.GeocoderStatus.OK) {
//store the parsed address-components as property of "that"
that.postData=that.parseAddressComponents(results[0].address_components);
that.map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: that.map,
position: results[0].geometry.location
});
} else {
that.postData={};
alert(status);
}
}
//geocoding
that.codeAddress=function() {
var address = [byId(this.opts.ids.uiAddr).value,
byId(this.opts.ids.uiZip).value].join(',');
//initialize geocoder on first run
if(!this.geocoder){this.geocoder=new goo.Geocoder();}
this.geocoder.geocode( { 'address': address, 'region': this.opts.region},
this.geoCallback);
}
//make "that" global when needed
if(ns)window[ns]=that;
//load-handler
goo.event.addDomListener(window, 'load',function(){
that.initialize();});
})
( //some properties for the object
{
lat:37.7789,
lng:-122.3917,
region:'US',
ids:{ map :'map_canvas',
btnGeo :'geobutton',
btnSend :'sendbutton',
uiAddr :'streetAddress',
uiZip :'zipCode'}
},
//supply a name for the object here when you want to make it global
null
);
/*]]>*/
</script>
<fieldset>
streetAddress:<input id="streetAddress" value="paisley park">
zipCode:<input id="zipCode" value="55422">
<input id="geobutton" type="button" value="geocode">
<input id="sendbutton" type="button" value="send">
</fieldset>
<div id="map_canvas" style="height:300px;"></div>
I am having trouble extracting data from the following function which only works with an alert(content) as the next line but obviously this has to be removed! What am I doing wrong please?
var address = [];
var content;
geocoder.geocode({'latLng': Marker.getPosition()}, function(responses, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (responses && responses.length > 0) {
address = (responses[0].formatted_address).split(',');
for (i =0; i < address.length; i++) {
content += '<div>' + address[i] + '</div>';
}
}
}
});
content += content '<br>Last line</div>';
The above line does not include the above geocode content at all.
Callback is async, you can use the value only inside the callback.
content += content '<br>Last line</div>';
Will execute BEFORE the callback fires.
Please read this regarding handling server data got by AJAX.
I have some jQuery code that uses Google Maps Geocoding API to convert an address to coordinates, then use alert() to show the result in popup window. Here is the code which works fine:
$("#searchbox_form #search_button").click(function(e){
e.preventDefault();
var address = $("#location").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$("input#user_lat").val(results[0].geometry.location.lat());
$("input#user_lng").val(results[0].geometry.location.lng());
alert("lat: " + $("input[name='user_lat']").val());
alert("lng: " + $("input[name='user_lng']").val());
}
});
});
However now I want jQuery to submit the form $searchbox_form after the user closes the alert box. However adding $("#searchbox_form").submit(); at the end of the code chunk submits the form before the alert box shows up. This also causes the form to be submitted before the Google Maps geocoder returns the result.
How can I allow the geocoder to return the result before the form gets submitted?
Same as the code above, but with 1 additional line to submit form at the end:
$("#searchbox_form #search_button").click(function(e){
e.preventDefault();
var address = $("#location").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$("input#user_lat").val(results[0].geometry.location.lat());
$("input#user_lng").val(results[0].geometry.location.lng());
alert("lat: " + $("input[name='user_lat']").val());
alert("lng: " + $("input[name='user_lng']").val());
}
});
$("#searchbox_form").submit(); //THIS IS THE ADDED LINE OF CODE!!
});
You need to move the submit within the callback to the geocode function. The reasoning is, it's asynchronous and not running in direct order, so it's calling the geocode and then immediately firing the submit. If you put it like below, the form will submit on callback and after the alerts (as alerts will block the thread).
$("#searchbox_form #search_button").click(function(e){
e.preventDefault();
var address = $("#location").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function(results, status) {
// This function is async
if (status == google.maps.GeocoderStatus.OK) {
$("input#user_lat").val(results[0].geometry.location.lat());
$("input#user_lng").val(results[0].geometry.location.lng());
alert("lat: " + $("input[name='user_lat']").val());
alert("lng: " + $("input[name='user_lng']").val());
$("#searchbox_form").submit();
}
});
});
Why don't you just submit it after you're done with your callback?
$("#searchbox_form #search_button").click(function(e){
e.preventDefault();
var address = $("#location").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$("input#user_lat").val(results[0].geometry.location.lat());
$("input#user_lng").val(results[0].geometry.location.lng());
alert("lat: " + $("input[name='user_lat']").val());
alert("lng: " + $("input[name='user_lng']").val());
$("#searchbox_form").submit();
}
});
});
I think geocoder.geocode is an asynchronous function. Therefore you need the submit after the alert boxes.
$("#searchbox_form #search_button").click(function (e) {
e.preventDefault();
var address = $("#location").val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$("input#user_lat").val(results[0].geometry.location.lat());
$("input#user_lng").val(results[0].geometry.location.lng());
alert("lat: " + $("input[name='user_lat']").val());
alert("lng: " + $("input[name='user_lng']").val());
$("#searchbox_form").submit();
}
});
});