I want to add info window to this example 'Places search box' https://developers.google.com/maps/documentation/javascript/examples/places-searchbox
and info window should be like this example which contains name with google link, address, telephone, rating and website https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-hotelsearch
Typically StackOverflow is not used to ask somebody to write code for you. You just need to combine these two examples to get the desired behavior.
That being said, below you can find the merged example, that introduces info windows from the second example to the first example.
var map, places, infoWindow;
function initAutocomplete() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -33.8688, lng: 151.2195},
zoom: 13,
mapTypeId: 'roadmap'
});
infoWindow = new google.maps.InfoWindow({
content: document.getElementById('info-content')
});
places = new google.maps.places.PlacesService(map);
// Create the search box and link it to the UI element.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
google.maps.event.clearListeners(marker, 'click');
marker.setMap(null);
});
markers = [];
// For each place, get the icon, name and location.
var bounds = new google.maps.LatLngBounds();
var count = 0;
places.forEach(function(place) {
if (!place.geometry) {
console.log("Returned place contains no geometry");
return;
}
var icon = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
markers.push(new google.maps.Marker({
map: map,
icon: icon,
title: place.name,
position: place.geometry.location
}));
markers[count].placeResult = place;
google.maps.event.addListener(markers[count], 'click', showInfoWindow);
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
count++;
});
map.fitBounds(bounds);
});
}
function showInfoWindow() {
var marker = this;
places.getDetails({placeId: marker.placeResult.place_id},
function(place, status) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
return;
}
infoWindow.open(map, marker);
buildIWContent(place);
});
}
function buildIWContent(place) {
document.getElementById('iw-icon').innerHTML = '<img class="hotelIcon" ' +
'src="' + place.icon + '"/>';
document.getElementById('iw-url').innerHTML = '<b><a href="' + place.url +
'">' + place.name + '</a></b>';
document.getElementById('iw-address').textContent = place.vicinity;
if (place.formatted_phone_number) {
document.getElementById('iw-phone-row').style.display = '';
document.getElementById('iw-phone').textContent =
place.formatted_phone_number;
} else {
document.getElementById('iw-phone-row').style.display = 'none';
}
// Assign a five-star rating to the hotel, using a black star ('✭')
// to indicate the rating the hotel has earned, and a white star ('✩')
// for the rating points not achieved.
if (place.rating) {
var ratingHtml = '';
for (var i = 0; i < 5; i++) {
if (place.rating < (i + 0.5)) {
ratingHtml += '✩';
} else {
ratingHtml += '✭';
}
document.getElementById('iw-rating-row').style.display = '';
document.getElementById('iw-rating').innerHTML = ratingHtml;
}
} else {
document.getElementById('iw-rating-row').style.display = 'none';
}
// The regexp isolates the first part of the URL (domain plus subdomain)
// to give a short URL for displaying in the info window.
if (place.website) {
var fullUrl = place.website;
var website = hostnameRegexp.exec(place.website);
if (website === null) {
website = 'http://' + place.website + '/';
fullUrl = website;
}
document.getElementById('iw-website-row').style.display = '';
document.getElementById('iw-website').textContent = website;
} else {
document.getElementById('iw-website-row').style.display = 'none';
}
}
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#description {
font-family: Roboto;
font-size: 15px;
font-weight: 300;
}
#infowindow-content .title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
.pac-card {
margin: 10px 10px 0 0;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
background-color: #fff;
font-family: Roboto;
}
#pac-container {
padding-bottom: 12px;
margin-right: 12px;
}
.pac-controls {
display: inline-block;
padding: 5px 11px;
}
.pac-controls label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
#title {
color: #fff;
background-color: #4d90fe;
font-size: 25px;
font-weight: 500;
padding: 6px 12px;
}
#target {
width: 345px;
}
.placeIcon {
width: 20px;
height: 34px;
margin: 4px;
}
.hotelIcon {
width: 24px;
height: 24px;
}
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map"></div>
<div style="display: none">
<div id="info-content">
<table>
<tr id="iw-url-row" class="iw_table_row">
<td id="iw-icon" class="iw_table_icon"></td>
<td id="iw-url"></td>
</tr>
<tr id="iw-address-row" class="iw_table_row">
<td class="iw_attribute_name">Address:</td>
<td id="iw-address"></td>
</tr>
<tr id="iw-phone-row" class="iw_table_row">
<td class="iw_attribute_name">Telephone:</td>
<td id="iw-phone"></td>
</tr>
<tr id="iw-rating-row" class="iw_table_row">
<td class="iw_attribute_name">Rating:</td>
<td id="iw-rating"></td>
</tr>
<tr id="iw-website-row" class="iw_table_row">
<td class="iw_attribute_name">Website:</td>
<td id="iw-website"></td>
</tr>
</table>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDztlrk_3CnzGHo7CFvLFqE_2bUKEq1JEU&libraries=places&callback=initAutocomplete"
async defer></script>
You can find this example on jsbin as well: http://jsbin.com/xipagud/edit?html,output
Hope this helps!
Related
I'm working on a Google Maps API program that provides a nearbySearch function based on longitude and latitude, and user given locations. It works almost exactly as intended, but there's one final part that I've been having a lot of trouble with, and that's resetting the markers. Here's a screenshot of the code when initially ran, the search works as intended, you can see the results to the right, and there's a section showing user locations (orange markers) and the number of users tied to these locations:
But when the user enters a latitude and longitude, the map will update, but nothing else will.
Something that I thought may help, and seems like it could've been close was setting an if else statement for the initMap function, and having an onclick function from the submit button change it to false, thus changing the starting lat & lng with the user lat & lng:
function initMap() {
// Create the map.
if (true)
var SHU = {
lat: lat,
lng: lng
}
else {
var SHU = {
lat: newLatlat,
lng: newLng
}};
But messing with the onclick function of submit just ended up ruining other aspects of the code, so I come asking for help. Here's the code, and it should run without issue, but you may need an API key of your own.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Base Mapper</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style id="compiled-css" type="text/css">
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding-top: 10px;
padding-left: 10px;
padding-right: 10px;
background-color: #ffd1b2
}
#right-panel {
font-family: 'Roboto', 'sans-serif';
line-height: 30px;
padding-left: 10px;
}
#right-panel select,
#right-panel input {
font-size: 15px;
}
#right-panel select {
width: 100%;
}
#right-panel i {
font-size: 12px;
}
#right-panel {
font-family: Arial, Helvetica, sans-serif;
position: absolute;
right: 5px;
top: 60%;
margin-top: -395px;
height: 650px;
width: 200px;
padding: 10px;
padding-left: 10px;
z-index: 10;
border: 1px solid #999;
background: #fff;
}
h2 {
font-size: 23px;
margin: 0 0 5px 0;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
height: 580px;
width: 200px;
overflow-y: scroll;
}
li {
background-color: #ffc965;
padding: 5px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
li:nth-child(odd) {
background-color: #fff065;
}
#more {
width: 100%;
margin: 5px 0 0 0;
}
input[type=text],
select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
background-color: #ffefe5
}
.container {
border-radius: 5px;
background-color: #ffd1b2
padding: 80px;
width: 80%
}
button {
width: 100%;
background-color: #8f20b6;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #cba00d;
}
table {
width: 100%;
background-color: #8f20b6;
color: white;
padding: 25px 0px;
margin: 8px 0;
border: none;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<form id="mapCenterForm" action="" onsubmit="return false;">
<label for="latitude">lat</label>
<input type="text" id="lat" name="latitude" placeholder="0.000000">
<label for="longitude">lng</label>
<input type="text" id="lng" name="longitude" placeholder="0.000000">
<br>
<button onclick="change_center(); return false">
Submit
</button>
</form>
<div id="map" style="height: 500px"></div>
</div>
<div id="right-panel">
<h2>Locations</h2>
<div id="number_results"></div>
<ul id="places"></ul>
<button id="more">More Results</button>
</div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIza...&callback=initMap" async defer></script>
<script type="text/javascript">
var blue_icon = 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png';
var orange_icon = 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png';
var map;
var lat = 41.18076;
var lng = -73.20537;
var userLoc = 0;
var userCount = 0;
var stopper = 1;
function initMap() {
// Create the map.
if (true)
var SHU = {
lat: lat,
lng: lng
}
else {
var SHU = {
lat: newLatlat,
lng: newLng
}};
map = new google.maps.Map(document.getElementById('map'), {
center: SHU,
zoom: 13
});
google.maps.event.addListener(map, 'click', function(e) {
document.getElementById('lat').value = e.latLng.lat();
document.getElementById('lng').value = e.latLng.lng();
})
// Create the places service.
var service = new google.maps.places.PlacesService(map);
var getNextPage = null;
var moreButton = document.getElementById('more');
moreButton.onclick = function() {
moreButton.disabled = true;
if (getNextPage) getNextPage();
};
service.nearbySearch({
location: SHU,
radius: 4000,
keyword: "(library) OR (hospital)"
},
function(results, status, pagination) {
if (status !== 'OK') return;
createMarkers(results);
moreButton.disabled = !pagination.hasNextPage;
getNextPage = pagination.hasNextPage && function() {
pagination.nextPage();
};
});
}
function createMarkers(places) {
var harry = new google.maps.Marker({
position: {lat: 41.18076, lng: -73.20537},
map: map,
icon: orange_icon,
title: 'Harry & Martha Richardson'
})
if (((lat>40.78076&&lat<41.58076)||(lng>-73.60537&&lng<-72.80537))&&(stopper==1))
{ userLoc = userLoc+1
userCount = userCount+2 };
var Maria = new google.maps.Marker({
position: {lat: 41.14055, lng: -73.26827},
map: map,
icon: orange_icon,
title: 'Maria Blane'
})
if (((lat>40.74055&&lat<41.54055)||(lng>-74.00537&&lng<-73.20537))&&(stopper==1))
{ userLoc = userLoc+1
userCount = userCount+1};
var Kent = new google.maps.Marker({
position: {lat: 41.19613, lng: -73.21837},
map: map,
icon: orange_icon,
title: 'Kent, Pedro, Natasha'
})
if (((lat>40.79613&&lat<41.59613)||(lng>-73.61837&&lng<-72.81837))&&(stopper==1))
{ userLoc = userLoc+1
userCount = userCount+3 };
var DummyVar1 = new google.maps.Marker({
position: {lat: 38.897957, lng: -77.036560},
map: map,
icon: orange_icon,
title: 'Dummy Name'
})
if (((lat>38.497957&&lat<39.297957)||(lng>-77.43656&&lng<-76.63656))&&(stopper==1))
{ userLoc = userLoc+1
userCount = userCount+100 };
var DummyVar2 = new google.maps.Marker({
position: {lat: 36.056595, lng: -112.125092},
map: map,
icon: orange_icon,
title: 'Dummier Name'
})
if ((lat>35.656595&&lat<36.456595)||(lng>-112.525092&&lng<-111.725092))
{ userLoc = userLoc+1
userCount = userCount+100
};
{ stopper = 0 };
var bounds = new google.maps.LatLngBounds();
var placesList = document.getElementById('places');
for (var i = 0, place; place = places[i]; i++) {
var image = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
var marker = new google.maps.Marker({
map: map,
icon: blue_icon,
title: place.name,
position: place.geometry.location
});
var li = document.createElement('li');
li.textContent = place.name;
placesList.appendChild(li);
document.getElementById('number_results').innerHTML = placesList.children.length + " returned";
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
document.getElementById("val").innerHTML = "Based on your latitude of " + lat + " and longitude of " + lng +
", the total places found is: " + (document.getElementById('places').children.length) + ". User locations: " + userLoc + ". Total users: " + userCount + ".";
}
function change_center() {
var newLat = parseFloat(document.getElementById("lat").value);
var newLng = parseFloat(document.getElementById("lng").value);
map.setCenter({
lat: newLat,
lng: newLng
});
return false;
}
</script>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "r96szuhx"
}], "*")
}
// always overwrite window.name, in case users try to set it manually
window.name = "result"
</script>
<table>
<tr>
<th id="val"></th>
</tr>
</table>
</body>
</html>
You need to re-run the query when the map center changes. I would suggest putting that query into a function you can call both places (and tracking the markers so you can remove them when you start a new query):
function nearbySearch() {
document.getElementById('places').innerHTML = "";
for (var i=0; i<markers.length;i++) {
markers[i].setMap(null);
}
markers = [];
// Create the places service.
var service = new google.maps.places.PlacesService(map);
var getNextPage = null;
var moreButton = document.getElementById('more');
moreButton.onclick = function() {
moreButton.disabled = true;
if (getNextPage) getNextPage();
};
service.nearbySearch({
location: map.getCenter(),
radius: 4000,
keyword: "(library) OR (hospital)"
},
function(results, status, pagination) {
if (status !== 'OK') return;
createMarkers(results);
moreButton.disabled = !pagination.hasNextPage;
getNextPage = pagination.hasNextPage && function() {
pagination.nextPage();
};
});
}
working code snippet:
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding-top: 10px;
padding-left: 10px;
padding-right: 10px;
background-color: #ffd1b2
}
#right-panel {
font-family: 'Roboto', 'sans-serif';
line-height: 30px;
padding-left: 10px;
}
#right-panel select,
#right-panel input {
font-size: 15px;
}
#right-panel select {
width: 100%;
}
#right-panel i {
font-size: 12px;
}
#right-panel {
font-family: Arial, Helvetica, sans-serif;
position: absolute;
right: 5px;
top: 60%;
margin-top: -395px;
height: 650px;
width: 200px;
padding: 10px;
padding-left: 10px;
z-index: 10;
border: 1px solid #999;
background: #fff;
}
h2 {
font-size: 23px;
margin: 0 0 5px 0;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
height: 580px;
width: 200px;
overflow-y: scroll;
}
li {
background-color: #ffc965;
padding: 5px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
li:nth-child(odd) {
background-color: #fff065;
}
#more {
width: 100%;
margin: 5px 0 0 0;
}
input[type=text],
select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
background-color: #ffefe5
}
.container {
border-radius: 5px;
background-color: #ffd1b2 padding: 80px;
width: 80%
}
button {
width: 100%;
background-color: #8f20b6;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #cba00d;
}
table {
width: 100%;
background-color: #8f20b6;
color: white;
padding: 25px 0px;
margin: 8px 0;
border: none;
cursor: pointer;
}
<div class="container">
<form id="mapCenterForm" action="" onsubmit="return false;">
<label for="latitude">lat</label>
<input type="text" id="lat" name="latitude" placeholder="0.000000">
<label for="longitude">lng</label>
<input type="text" id="lng" name="longitude" placeholder="0.000000">
<br>
<button onclick="change_center(); return false">
Submit
</button>
</form>
<div id="map" style="height: 500px"></div>
</div>
<div id="right-panel">
<h2>Locations</h2>
<div id="number_results"></div>
<ul id="places"></ul>
<button id="more">More Results</button>
</div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap" async defer></script>
<script type="text/javascript">
var blue_icon = 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png';
var orange_icon = 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png';
var map;
var lat = 41.18076;
var lng = -73.20537;
var userLoc = 0;
var userCount = 0;
var stopper = 1;
var markers = [];
function initMap() {
// Create the map.
var SHU = {
lat: lat,
lng: lng
}
map = new google.maps.Map(document.getElementById('map'), {
center: SHU,
zoom: 13
});
google.maps.event.addListener(map, 'click', function(e) {
document.getElementById('lat').value = e.latLng.lat();
document.getElementById('lng').value = e.latLng.lng();
})
nearbySearch();
}
function createMarkers(places) {
var harry = new google.maps.Marker({
position: {
lat: 41.18076,
lng: -73.20537
},
map: map,
icon: orange_icon,
title: 'Harry & Martha Richardson'
})
if (((lat > 40.78076 && lat < 41.58076) || (lng > -73.60537 && lng < -72.80537)) && (stopper == 1)) {
userLoc = userLoc + 1
userCount = userCount + 2
};
var Maria = new google.maps.Marker({
position: {
lat: 41.14055,
lng: -73.26827
},
map: map,
icon: orange_icon,
title: 'Maria Blane'
})
if (((lat > 40.74055 && lat < 41.54055) || (lng > -74.00537 && lng < -73.20537)) && (stopper == 1)) {
userLoc = userLoc + 1
userCount = userCount + 1
};
var Kent = new google.maps.Marker({
position: {
lat: 41.19613,
lng: -73.21837
},
map: map,
icon: orange_icon,
title: 'Kent, Pedro, Natasha'
})
if (((lat > 40.79613 && lat < 41.59613) || (lng > -73.61837 && lng < -72.81837)) && (stopper == 1)) {
userLoc = userLoc + 1
userCount = userCount + 3
};
var DummyVar1 = new google.maps.Marker({
position: {
lat: 38.897957,
lng: -77.036560
},
map: map,
icon: orange_icon,
title: 'Dummy Name'
})
if (((lat > 38.497957 && lat < 39.297957) || (lng > -77.43656 && lng < -76.63656)) && (stopper == 1)) {
userLoc = userLoc + 1
userCount = userCount + 100
};
var DummyVar2 = new google.maps.Marker({
position: {
lat: 36.056595,
lng: -112.125092
},
map: map,
icon: orange_icon,
title: 'Dummier Name'
})
if ((lat > 35.656595 && lat < 36.456595) || (lng > -112.525092 && lng < -111.725092)) {
userLoc = userLoc + 1
userCount = userCount + 100
}; {
stopper = 0
};
var bounds = new google.maps.LatLngBounds();
var placesList = document.getElementById('places');
for (var i = 0, place; place = places[i]; i++) {
var image = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
var marker = new google.maps.Marker({
map: map,
icon: blue_icon,
title: place.name,
position: place.geometry.location
});
markers.push(marker);
var li = document.createElement('li');
li.textContent = place.name;
placesList.appendChild(li);
document.getElementById('number_results').innerHTML = placesList.children.length + " returned";
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
document.getElementById("val").innerHTML = "Based on your latitude of " + lat + " and longitude of " + lng +
", the total places found is: " + (document.getElementById('places').children.length) + ". User locations: " + userLoc + ". Total users: " + userCount + ".";
}
function change_center() {
var newLat = parseFloat(document.getElementById("lat").value);
var newLng = parseFloat(document.getElementById("lng").value);
map.setCenter({
lat: newLat,
lng: newLng
});
nearbySearch();
return false;
}
function nearbySearch() {
document.getElementById('places').innerHTML = "";
for (var i=0; i<markers.length;i++) {
markers[i].setMap(null);
}
markers = [];
// Create the places service.
var service = new google.maps.places.PlacesService(map);
var getNextPage = null;
var moreButton = document.getElementById('more');
moreButton.onclick = function() {
moreButton.disabled = true;
if (getNextPage) getNextPage();
};
service.nearbySearch({
location: map.getCenter(),
radius: 4000,
keyword: "(library) OR (hospital)"
},
function(results, status, pagination) {
if (status !== 'OK') return;
createMarkers(results);
moreButton.disabled = !pagination.hasNextPage;
getNextPage = pagination.hasNextPage && function() {
pagination.nextPage();
};
});
}
</script>
<table>
<tr>
<th id="val"></th>
</tr>
</table>
I am providing a form to a user which takes some information about the user.
Instead of taking the address by providing them options like drop box which includes many countries,cities,states and area, I would provide them Google Map so that user can share their location and when user submit the form, then I must be able to get country,city,state,area and latitude and longitude and store that in MySQL database
When a user share their location, below codes gives all the required data, like country,state,city,area,pin-code, latitude,longitude and many more....
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Places Search Box</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#description {
font-family: Roboto;
font-size: 15px;
font-weight: 300;
}
#infowindow-content .title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
.pac-card {
margin: 10px 10px 0 0;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
background-color: #fff;
font-family: Roboto;
}
#pac-container {
padding-bottom: 12px;
margin-right: 12px;
}
.pac-controls {
display: inline-block;
padding: 5px 11px;
}
.pac-controls label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
#title {
color: #fff;
background-color: #4d90fe;
font-size: 25px;
font-weight: 500;
padding: 6px 12px;
}
#target {
width: 345px;
}
</style>
</head>
<body>
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map"></div>
<script>
// This example adds a search box to a map, using the Google Place Autocomplete
// feature. People can enter geographical searches. The search box will return a
// pick list containing a mix of places and predicted search terms.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initAutocomplete() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -33.8688, lng: 151.2195},
zoom: 13,
mapTypeId: 'roadmap'
});
// Create the search box and link it to the UI element.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
// For each place, get the icon, name and location.
var bounds = new google.maps.LatLngBounds();
places.forEach(function(place) {
if (!place.geometry) {
console.log("Returned place contains no geometry");
return;
}
var icon = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
markers.push(new google.maps.Marker({
map: map,
icon: icon,
title: place.name,
position: place.geometry.location
}));
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
map.fitBounds(bounds);
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"
async defer></script>
</body>
</html>
This question already has an answer here:
How to get country from google maps api?
(1 answer)
Closed 4 years ago.
I'm working with google map API(geocoding) and I noticed the following. If I print the array for "x" address, it prints an array of objects of size 9. where the country is in the index 6. If I enter some other "y" address, sometimes the array of objects is less than 9 and the index to get the country is not 6 anymore. I have tried with different addresses as some of them have the size consistent as 9 some of them at 6 some of them 7 and so on. Is there a set way for me to access the country without having to check the size of the array and avoid this issue?
my code
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
this.addressArray = place.address_components;
if(this.addressArray.length === 9) {
this.country = this.addressArray[6].short_name;
this.zipcode = this.addressArray[7].short_name;
} else {
this.country = this.addressArray[5].short_name;
this.zipcode = this.addressArray[6].short_name;
}
I figured I can use place.formatted_address and access the last word which is always the country, but for zipcode and some other information on the address the order is not always the same.
Below is an example of the structure of the array of objects I'm printing.
I thought about filtering the array to find the index of types that contains the word country,zipcode, etc and based on the index returned get the country or whatever I want to retrieve. I wonder if there's an easier way to accomplish this straight from the google API geocode.
This question How to get country from google maps api? talks about someone entering the address. My application uses google autocomplete. I thought the API was smarter to handle the missing data of people not entering a complete address. Also, the answer address in that question is part of my explanation of my question of me saying I knew I could filter the array
related question: Wrong country code returned by Google Geocoder
You need to parse through the address_components array's types, looking for the entry with a type of country.
var country = '';
for (var i = 0; i < place.address_components.length; i++) {
for (var j = 0; j < place.address_components[i].types.length; j++) {
if (place.address_components[i].types[j] == "country") {
country = place.address_components[i];
}
}
}
document.getElementById("country").innerHTML = country.long_name +" (" + country.short_name +")";
proof of concept fiddle
code snippet:
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: -33.8688,
lng: 151.2195
},
zoom: 13
});
var input = document.getElementById('pac-input');
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo('bounds', map);
var infowindow = new google.maps.InfoWindow();
var infowindowContent = document.getElementById('infowindow-content');
infowindow.setContent(infowindowContent);
var marker = new google.maps.Marker({
map: map,
anchorPoint: new google.maps.Point(0, -29)
});
autocomplete.addListener('place_changed', function() {
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert("No details available for input: '" + place.name + "'");
return;
}
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17); // Why 17? Because it looks good.
}
marker.setPosition(place.geometry.location);
marker.setVisible(true);
var country = '';
for (var i = 0; i < place.address_components.length; i++) {
for (var j = 0; j < place.address_components[i].types.length; j++) {
if (place.address_components[i].types[j] == "country") {
country = place.address_components[i];
}
}
}
document.getElementById("country").innerHTML = country.long_name + " (" + country.short_name + ")";
infowindowContent.children['place-icon'].src = place.icon;
infowindowContent.children['place-name'].textContent = place.name;
infowindowContent.children['place-address'].textContent = country.long_name;
infowindow.open(map, marker);
});
}
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#description {
font-family: Roboto;
font-size: 30px;
font-weight: 300;
}
#infowindow-content .title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
.pac-card {
margin: 10px 10px 0 0;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
background-color: #fff;
font-family: Roboto;
}
#pac-container {
padding-bottom: 12px;
margin-right: 12px;
}
.pac-controls {
display: inline-block;
padding: 5px 11px;
}
.pac-controls label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
#title {
color: #fff;
background-color: #4d90fe;
font-size: 25px;
font-weight: 500;
padding: 6px 12px;
}
<div class="pac-card" id="pac-card">
<div>
<div id="type-selector" class="pac-controls">
</div>
<div id="pac-container">
<input id="pac-input" type="text" placeholder="Enter a location">
</div>
</div>
</div>
<div id="country"></div>
<div id="map"></div>
<div id="infowindow-content">
<img src="" width="16" height="16" id="place-icon">
<span id="place-name" class="title"></span><br>
<span id="place-address"></span>
</div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk" async defer></script>
I am using Google Places autocomplete to select cities by name. Currently it displays only the city name and the country it belongs to, in the suggestions drop down.
I have checked and found that the "address_components" object, that gets populated when a city is selected, has additional attibutes like state/province and other parts of the address. So, it is clear that the Google's API provide additional information other than merely the city and country names.
What I am trying to achieve is, displaying a couple of those additional data in the suggestions dropdown.
Is there a way to do that?
(I have marked on the screenshot where I need to display the additional attributes)
Here is the code.
<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places&callback=initAutocomplete&query=locality" async defer></script>
<script>
var searchBox;
function initAutocomplete() {
var options = {types: ['(cities)']};
var input = document.getElementById('placeAuto');
searchBox = new google.maps.places.Autocomplete(input);
searchBox.addListener('place_changed', fillInAddress);
}
function fillInAddress()
{
var place = searchBox.getPlace();
console.log(place);
}
</script>
As I commented already, you can do that by using the Autocomplete and Places services and the getPlacePredictions method, but I would not recommend this approach as it will make a high number of requests to the API (one for each result, each time a user types something in the address field).
View the snippet in full screen mode as it won't fit hereunder or check it on JSFiddle.
In this example I have added the place latitude and longitude in the autocomplete results.
var autocompleteService, placesService, results, map;
function initialize() {
results = document.getElementById('results');
var mapOptions = {
zoom: 5,
center: new google.maps.LatLng(50, 50)
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// Bind listener for address search
google.maps.event.addDomListener(document.getElementById('address'), 'input', function() {
results.style.display = 'block';
getPlacePredictions(document.getElementById('address').value);
});
// Show results when address field is focused (if not empty)
google.maps.event.addDomListener(document.getElementById('address'), 'focus', function() {
if (document.getElementById('address').value !== '') {
results.style.display = 'block';
getPlacePredictions(document.getElementById('address').value);
}
});
// Hide results when click occurs out of the results and inputs
google.maps.event.addDomListener(document, 'click', function(e) {
if ((e.target.parentElement.className !== 'pac-container') && (e.target.parentElement.className !== 'pac-item') && (e.target.tagName !== 'INPUT')) {
results.style.display = 'none';
}
});
autocompleteService = new google.maps.places.AutocompleteService();
placesService = new google.maps.places.PlacesService(map);
}
// Get place predictions
function getPlacePredictions(search) {
autocompleteService.getPlacePredictions({
input: search,
types: ['geocode']
}, callback);
}
// Place search callback
function callback(predictions, status) {
// Empty results container
results.innerHTML = '';
// Place service status error
if (status != google.maps.places.PlacesServiceStatus.OK) {
results.innerHTML = '<div class="pac-item pac-item-error">Your search returned no result. Status: ' + status + '</div>';
return;
}
// Build output for each prediction
for (var i = 0, prediction; prediction = predictions[i]; i++) {
// Get place details to inject more details in autocomplete results
placesService.getDetails({
placeId: prediction.place_id
}, function(place, serviceStatus) {
if (serviceStatus === google.maps.places.PlacesServiceStatus.OK) {
// Create a new result element
var div = document.createElement('div');
// Insert inner HTML
div.innerHTML += '<span class="pac-icon pac-icon-marker"></span>' + place.adr_address + '<div class="pac-item-details">Lat: ' + place.geometry.location.lat().toFixed(3) + ', Lng: ' + place.geometry.location.lng().toFixed(3) + '</div>';
div.className = 'pac-item';
// Bind a click event
div.onclick = function() {
var center = place.geometry.location;
var marker = new google.maps.Marker({
position: center,
map: map
});
map.setCenter(center);
}
// Append new element to results
results.appendChild(div);
}
});
}
}
google.maps.event.addDomListener(window, 'load', initialize);
body,
html {
font-family: Arial, sans-serif;
padding: 0;
margin: 0;
height: 100%;
}
#map-canvas {
height: 150px;
margin-bottom: 5px;
}
table {
border-collapse: collapse;
margin-left: 20px;
}
table td {
padding: 3px 5px;
}
label {
display: inline-block;
width: 160px;
font-size: 11px;
color: #777;
}
input {
border: 1px solid #ccc;
width: 170px;
padding: 3px 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
}
.pac-container {
background-color: #fff;
z-index: 1000;
border-radius: 2px;
font-size: 11px;
box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
width: 350px;
}
.pac-icon {
width: 15px;
height: 20px;
margin-right: 7px;
margin-top: 6px;
display: inline-block;
vertical-align: top;
background-image: url(https://maps.gstatic.com/mapfiles/api-3/images/autocomplete-icons.png);
background-size: 34px;
}
.pac-icon-marker {
background-position: -1px -161px;
}
.pac-item {
cursor: pointer;
padding: 0 4px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
line-height: 30px;
vertical-align: middle;
text-align: left;
border-top: 1px solid #e6e6e6;
color: #999;
}
.pac-item:hover {
background-color: #efefef;
}
.pac-item-details {
color: lightblue;
padding-left: 22px;
}
.pac-item-error,
.pac-item-error:hover {
color: #aaa;
padding: 0 5px;
cursor: default;
background-color: #fff;
}
<div id="map-canvas"></div>
<table>
<tr>
<td>
<label for="address">Address:</label>
</td>
</tr>
<tr>
<td>
<input id="address" placeholder="Enter address" type="text" tabindex="1" />
</td>
</tr>
<tr>
<td colspan="2">
<div id="results" class="pac-container"></div>
</td>
</tr>
</table>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
I am using GoogleMaps with AutoComplete and Directions services to draw a route between two markers (places). The example on google maps documentation has two input fields, one for origin and other for destination. I have destination LatLong. How can I fix the destination with these latLong and draw route when user selects origin.
destination lat/lng: latitude: 25.116810, longitude: 55.123562
link to jsfiddle JsFiddle
<!DOCTYPE html>
<html>
<head>
<title>Place Autocomplete</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#origin-input,
#destination-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 200px;
}
#origin-input:focus,
#destination-input:focus {
border-color: #4d90fe;
}
#mode-selector {
color: #fff;
background-color: #4d90fe;
margin-left: 12px;
padding: 5px 11px 0px 11px;
}
#mode-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
</style>
</head>
<body>
<input id="origin-input" class="controls" type="text"
placeholder="Enter an origin location">
<input id="destination-input" class="controls" type="text"
placeholder="Enter a destination location">
<div id="mode-selector" class="controls">
<input type="radio" name="type" id="changemode-walking" checked="checked">
<label for="changemode-walking">Walking</label>
<input type="radio" name="type" id="changemode-transit">
<label for="changemode-transit">Transit</label>
<input type="radio" name="type" id="changemode-driving">
<label for="changemode-driving">Driving</label>
</div>
<div id="map"></div>
<script>
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
mapTypeControl: false,
center: {lat: -33.8688, lng: 151.2195},
zoom: 13
});
new AutocompleteDirectionsHandler(map);
}
/**
* #constructor
*/
function AutocompleteDirectionsHandler(map) {
this.map = map;
this.originPlaceId = null;
this.destinationPlaceId = null;
this.travelMode = 'WALKING';
var originInput = document.getElementById('origin-input');
var destinationInput = document.getElementById('destination-input');
var modeSelector = document.getElementById('mode-selector');
this.directionsService = new google.maps.DirectionsService;
this.directionsDisplay = new google.maps.DirectionsRenderer;
this.directionsDisplay.setMap(map);
var originAutocomplete = new google.maps.places.Autocomplete(
originInput, {placeIdOnly: true});
var destinationAutocomplete = new google.maps.places.Autocomplete(
destinationInput, {placeIdOnly: true});
this.setupClickListener('changemode-walking', 'WALKING');
this.setupClickListener('changemode-transit', 'TRANSIT');
this.setupClickListener('changemode-driving', 'DRIVING');
this.setupPlaceChangedListener(originAutocomplete, 'ORIG');
this.setupPlaceChangedListener(destinationAutocomplete, 'DEST');
this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(originInput);
this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(destinationInput);
this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(modeSelector);
}
// Sets a listener on a radio button to change the filter type on Places
// Autocomplete.
AutocompleteDirectionsHandler.prototype.setupClickListener = function(id, mode) {
var radioButton = document.getElementById(id);
var me = this;
radioButton.addEventListener('click', function() {
me.travelMode = mode;
me.route();
});
};
AutocompleteDirectionsHandler.prototype.setupPlaceChangedListener = function(autocomplete, mode) {
var me = this;
autocomplete.bindTo('bounds', this.map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (!place.place_id) {
window.alert("Please select an option from the dropdown list.");
return;
}
if (mode === 'ORIG') {
me.originPlaceId = place.place_id;
} else {
me.destinationPlaceId = place.place_id;
}
me.route();
});
};
AutocompleteDirectionsHandler.prototype.route = function() {
if (!this.originPlaceId || !this.destinationPlaceId) {
return;
}
var me = this;
this.directionsService.route({
origin: {'placeId': this.originPlaceId},
destination: {'placeId': this.destinationPlaceId},
travelMode: this.travelMode
}, function(response, status) {
if (status === 'OK') {
me.directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=your_api_key&libraries=places&callback=initMap"
async defer></script>
</body>
</html>
set the desired destination (hard code it)
destination: new google.maps.LatLng(25.116810, 55.123562);
remove the autocomplete associated with the destination
Note that for some reason your destination doesn't work for walking directions, so you may want to remove the travelMode selection.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
mapTypeControl: false,
center: {
lat: 25.116810,
lng: 55.123562
},
zoom: 13
});
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(25.116810, 55.123562)
});
new AutocompleteDirectionsHandler(map);
}
/**
* #constructor
*/
function AutocompleteDirectionsHandler(map) {
this.map = map;
this.originPlaceId = null;
this.travelMode = 'DRIVING';
var originInput = document.getElementById('origin-input');
this.directionsService = new google.maps.DirectionsService;
this.directionsDisplay = new google.maps.DirectionsRenderer;
this.directionsDisplay.setMap(map);
var originAutocomplete = new google.maps.places.Autocomplete(
originInput, {
placeIdOnly: true
});
this.setupPlaceChangedListener(originAutocomplete, 'ORIG');
this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(originInput);
}
// Sets a listener on a radio button to change the filter type on Places
// Autocomplete.
AutocompleteDirectionsHandler.prototype.setupClickListener = function(id, mode) {
var radioButton = document.getElementById(id);
var me = this;
radioButton.addEventListener('click', function() {
me.travelMode = mode;
me.route();
});
};
AutocompleteDirectionsHandler.prototype.setupPlaceChangedListener = function(autocomplete, mode) {
var me = this;
autocomplete.bindTo('bounds', this.map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (!place.place_id) {
window.alert("Please select an option from the dropdown list.");
return;
}
me.originPlaceId = place.place_id;
me.route();
});
};
AutocompleteDirectionsHandler.prototype.route = function() {
if (!this.originPlaceId) {
return;
}
var me = this;
this.directionsService.route({
origin: {
'placeId': this.originPlaceId
},
destination: new google.maps.LatLng(25.116810, 55.123562),
travelMode: this.travelMode
}, function(response, status) {
if (status === 'OK') {
me.directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
};
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#origin-input,
#destination-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 200px;
}
#origin-input:focus,
#destination-input:focus {
border-color: #4d90fe;
}
#mode-selector {
color: #fff;
background-color: #4d90fe;
margin-left: 12px;
padding: 5px 11px 0px 11px;
}
#mode-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
<!DOCTYPE html>
<html>
<head>
<title>Place Autocomplete</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
</style>
</head>
<body>
<input id="origin-input" class="controls" type="text" placeholder="Enter an origin location">
<div id="map"></div>
<script>
</script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap" async defer></script>
</body>
</html>
In
this.directionsService.route({
origin: {'placeId': this.originPlaceId},
destination: {'placeId': this.destinationPlaceId},
travelMode: this.travelMode
}, function(response, status) {
In destination substitude with a LatLng:
destination: {lat: 25.116810, lng: 55.123562}
and you can erase input for destination or any event associated to get this field from user.