fill google maps autocomplete with prediction results - google-maps

What I have at the moment is a place autocomplete which displays results for one country.
What I want to do is make it display results for more countries (limited to 2 or 3).
As I understand it, this is not possible with the current version of the autocomplete ( https://code.google.com/p/gmaps-api-issues/issues/detail?id=4233)
So what I'm going to do is get two lists of predictions and display those instead of the autocomplete result.
Is there any way to trigger the dropdown part of the autocomplete and populate it with the predictionslist?
triggered code in the onChange of the input:
var inputData = this.value;
var options = {
componentRestrictions: { country: "be" }
};
service = new google.maps.places.AutocompleteService();
var request = {
input: inputData,
componentRestrictions: {country: 'be'},
};
var secondaryRequest = {
input: inputData,
componentRestrictions: {country: 'lu'},
};
service.getPlacePredictions(request, callback);
service.getPlacePredictions(secondaryRequest, callback);
callback function:
function callback(predictions, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
//here I need to display that dropdown if it isn't already
// and then add the results of the current predictions.
}
UPDATE
Multiple countries filter in place autocomplete was introduced in version 3.27 of Maps JavaScript API in January 2017:
You can now restrict Autocomplete predictions to only surface from multiple countries. You can do this by specifying up to 5 countries in the componentRestrictions field of the AutocompleteOptions.
source: https://developers.google.com/maps/documentation/javascript/releases#327

Here's my demo solution. As mentioned in the comment. it uses several calls to get predictions and build up the result list with them. When a result is selected the address is geocoded.
This means 3 calls instead of 1 with the autocomplete, but so far I haven't found a way around it.
<!DOCTYPE html>
<html>
<head>
<title>Retrieving Autocomplete Predictions</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places&v=3.exp"></script>
<script>
function initialize() {
$("#place").live("keyup", function (evt) {
// Clear any previously set timer before setting a new one
window.clearTimeout($(this).data("timeout"));
$(this).data("timeout", setTimeout(function () {
//whe the timeout has expired get the predictions
var inputData = $("#place").val();
service = new google.maps.places.AutocompleteService();
var request = {
input: inputData,
componentRestrictions: {country: 'be'},
};
var secondaryRequest = {
input: inputData,
componentRestrictions: {country: 'lu'},
};
$('#resultWindow').empty();
service.getPlacePredictions(request, callback);
service.getPlacePredictions(secondaryRequest, callback);
}, 1000));
});
function callback(predictions, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
console.log(status);
return;
}
var resultHTML = '';
for (var i = 0, prediction; prediction = predictions[i]; i++) {
resultHTML += '<div>' + prediction.description + '</div>';
}
if($('#resultWindow').html() != undefined && $('#resultWindow').html() != ''){
resultHTML = $('#resultWindow').html()+ resultHTML;
}
if(resultHTML != undefined && resultHTML != ''){
$('#resultWindow').html(resultHTML).show();
}
//add the "powered by google" image at the bottom -> required!!
if($('#resultWindow').html() != undefined){
$('#resultWindow #googleImage').remove();
var imageHtml = $('#resultWindow').html() + '<img id="googleImage" src="powered-by-google-on-white2.png"/>';
$('#resultWindow').html(imageHtml);
}
}
function geocodeAddress(address) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function (results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
$('#latitude').val(results[0].geometry.location.lat());
$('#longitude').val(results[0].geometry.location.lng());
}
else {
console.log("Error: " + google.maps.GeocoderStatus);
}
});
}
$('#resultWindow div').live('click',function(){
//get the coördinates for the selected (clicked) address
$('#resultWindow').hide();
var address = $(this).text();
var addressParts = address.split(',');
$('#country').val(addressParts[2]);
$('#city').val(addressParts[1]);
$('#place').val(addressParts[0]);
if(address != ''){
geocodeAddress(address);
}
});
/*end custom autocomplete stuff*/
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<style type="text/css">
#resultWindow{
position: fixed;
/* top: 0;
left: 0;
width: 100%;
height: 100%;*/
background-color: #fff;
filter:alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
z-index: 10000;
border: 1px solid black;
color:black;
display:none;
}
</style>
</head>
<body>
<div id="placeholder">
<input type="text" id="place" style="width:200px;"/>
<label for="latitude">Latitude</label>
<input type="text" id="latitude"/>
<label for="longitude">Longitude</label>
<input type="text" id="longitude"/>
<label for="city">city</label>
<input type="text" id="city"/>
<label for="country">selected country</label>
<input type="text" id="country"/>
<div id="resultWindow"></div>
</div>
</body>
</html>

Related

Google Maps set a text field value when address is selected

I'm trying to work out how to set the value of a text field called rehabGroup when I do an search for an address.
The autocomplete form I'm using consists of 2 maps.
I need to take the value from the locality returned result and use it to search through a list of names to return the result to a text field.
I can do it with an autocomplete search but I really need it to do it automatically when the result from the search is selected.
This is a snippet of the HTML
<div id="map2"></div>
<div class="form-group">
<label class="control-label" for="autocomplete2">Search for Encounter Address</label>
<i class="h5 fas fa-map-pin"></i>
<div class="input-group">
<input id="autocomplete2" />
</div>
</div>
<div class="form-group">
<label class="control-label" for="locality">Town/Suburb</label>
<i class="h5 far fa-map"></i>
<div class="input-group">
<input type="text" class=" form-control rounded" id="locality2" name="locality2" placeholder="Town of the rescue" data-toggle="tooltip" title="Town of rescue" />
</div>
</div>
<div class="form-group">
<label class="control-label" for="rehabGroup">Rehab Group</label>
<i class="h5 fas fa-map-pin"></i>
<div class="input-group">
<input type="text" id="rehabGroup" name="rehabGroup" value="" />
</div>
</div>
This is the code i've been using
<script>
$(function() {
$('#locality2').autocomplete({
source: 'ajax.php',
minLength: 3,
change: function (event, ui) {
if (!ui.item) {
$(this).val('');
$(this).focus();
}
},
select: function(event, ui) {
$('#rehabGroup').val(ui.item.rehabGroup);
}
});
});
let placeSearch, autocomplete, autocomplete2;
let componentForm = {
subpremise: 'long_name',
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
administrative_area_level_2: 'long_name',
country: 'long_name',
postal_code: 'short_name',
latitude: 'long_name',
longitude: 'short_name'
};
let defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-32.889049, 151.600815),
new google.maps.LatLng(-32.506633, 152.340289)
);
let map1 = new google.maps.Map(document.getElementById('map1'), {
center: {
lat: -32.732140,
lng: 152.039616
},
zoom: 11
});
let map2 = new google.maps.Map(document.getElementById('map2'), {
center: {
lat: -32.732140,
lng: 152.039616
},
zoom: 11
});
let marker1 = new google.maps.Marker({
map: map1,
draggable: true
});
let marker2 = new google.maps.Marker({
map: map2,
draggable: true
});
google.maps.event.addListener(marker1, 'dragend',
function(marker1) {
let latLng1 = marker1.latLng;
currentLatitude1 = latLng1.lat();
currentLongitude1 = latLng1.lng();
$('#lat').val((currentLatitude1).toFixed(6));
$('#lng').val((currentLongitude1).toFixed(6));
}
);
google.maps.event.addListener(marker2, 'dragend',
function(marker2) {
let latLng2 = marker2.latLng;
currentLatitude2 = latLng2.lat();
currentLongitude2 = latLng2.lng();
$('#lat2').val((currentLatitude2).toFixed(6));
$('#lng2').val((currentLongitude2).toFixed(6));
}
);
function initAutocomplete() {
// Create the autocomplete object, restricting the search to geographical
// location types.
autocomplete = new google.maps.places.Autocomplete(
/** #type {!HTMLInputElement} */
(document.getElementById('autocomplete')), {
bounds: defaultBounds,
types: [
'geocode'
],
strictBounds: true,
componentRestrictions: {
country: 'au'
}
});
// When the user selects an address from the dropdown, populate the address
// fields in the form.
autocomplete.addListener('place_changed', function() {
fillInAddress(autocomplete, '');
});
autocomplete2 = new google.maps.places.Autocomplete(
/** #type {!HTMLInputElement} */
(document.getElementById('autocomplete2')), {
bounds: defaultBounds,
types: [
'geocode'
],
strictBounds: true,
componentRestrictions: {
country: 'au'
}
});
autocomplete2.addListener('place_changed', function() {
fillInAddress(autocomplete2, '2');
});
}
function fillInAddress(autocomplete, unique) {
// Get the place details from the autocomplete object.
let place = autocomplete.getPlace();
if (unique === '2'){
if (place.geometry.viewport) {
map2.fitBounds(place.geometry.viewport);
} else {
map2.setCenter(place.geometry.location);
map2.setZoom(14);
}
marker2.setPosition(place.geometry.location);
marker2.setVisible(true);
}else{
if (place.geometry.viewport) {
map1.fitBounds(place.geometry.viewport);
} else {
map1.setCenter(place.geometry.location);
map1.setZoom(14);
}
marker1.setPosition(place.geometry.location);
marker1.setVisible(true);
}
for (let component in componentForm) {
if (!!document.getElementById(component + unique)) {
document.getElementById(component + unique).value = '';
document.getElementById(component + unique).disabled = false;
}
}
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (let i = 0; i < place.address_components.length; i++) {
let addy = '';
let addressTypes = place.address_components[i].types;
for (let j = 0; j < addressTypes.length; j++) {
let addressType = addressTypes[j];
if (componentForm[addressType] && document.getElementById(addressType + unique)) {
addy = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType + unique).value = addy;
}
}
}
document.getElementById('lat' + unique).value = place.geometry.location.lat().toFixed(6);
document.getElementById('lng' + unique).value = place.geometry.location.lng().toFixed(6);
}
google.maps.event.addDomListener(window, 'load', initAutocomplete);
</script>
TIA
Looks like you're able to populate an address form successfully once an address is selected from the Autocomplete dropdown. You just need to add another step to the to fillInAddress() when you find the locality component of the address to call your custom function that searches for your group names and populates the text field.
function fillInAddress(autocomplete, unique) {
// Get the place details from the autocomplete object.
let place = autocomplete.getPlace();
if (unique === '2'){
if (place.geometry.viewport) {
map2.fitBounds(place.geometry.viewport);
} else {
map2.setCenter(place.geometry.location);
map2.setZoom(14);
}
marker2.setPosition(place.geometry.location);
marker2.setVisible(true);
}else{
if (place.geometry.viewport) {
map1.fitBounds(place.geometry.viewport);
} else {
map1.setCenter(place.geometry.location);
map1.setZoom(14);
}
marker1.setPosition(place.geometry.location);
marker1.setVisible(true);
}
for (let component in componentForm) {
if (!!document.getElementById(component + unique)) {
document.getElementById(component + unique).value = '';
document.getElementById(component + unique).disabled = false;
}
}
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (let i = 0; i < place.address_components.length; i++) {
let addy = '';
let addressTypes = place.address_components[i].types;
for (let j = 0; j < addressTypes.length; j++) {
let addressType = addressTypes[j];
if (componentForm[addressType] && document.getElementById(addressType + unique)) {
addy = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType + unique).value = addy;
}
if (addressType == 'locality') {
// Perform your custom search on this locality and populate the result in text field rehabGroup
let locality = place.address_components[i]['long_name'];
let result = yourCustomSearch(locality);
document.getElementbyId('rehabGroup').value = result;
}
}
}
document.getElementById('lat' + unique).value = place.geometry.location.lat().toFixed(6);
document.getElementById('lng' + unique).value = place.geometry.location.lng().toFixed(6);
}
Thank's, I've gotten it to work but it happens on both the locality and locality2 fields . I'll try and sort it out from there.
if (addressType === 'locality') {
// Perform your custom search on this locality and populate the result in text field rehabGroup
let locality2 = place.address_components[i]['long_name'];
//Carry out a GET Ajax request using JQuery
$.ajax({
//The URL of the PHP file that searches MySQL.
type: 'GET',
url: 'ajax.php',
data: {
locality2: locality2
},
success: function(data){
let obj = data;
alert(cut);
document.getElementById('rehabGroup').value = cut;
}
});
}

Google Maps API v3 – filtering markers using checkboxes (multiple tags per marker)

I've built some filtering for a Google Map (v3 API) which is working with the code below but I want to expand on this. Some markers have multiple 'tags' assigned to them (and not just one) so if one of the checkboxes is turned off, and the marker has one of those tags, it should remain visible unless all it's tags are turned off.
An example of a marker's filter type could be
filter: {type: "1036|1102"}
or
filter: {type: "1033"}
Any below is an example of how the filters look and the JS.
<div class="filters">
<ul class="tags">
<li><label><input type="checkbox" value="1036" checked="checked" />Film</label></li>
<li><label><input type="checkbox" value="1102" checked="checked" />Heritage</label></li>
<li><label><input type="checkbox" value="1038" checked="checked" />Music</label></li>
<li><label><input type="checkbox" value="1075" checked="checked" />Shops</label></li>
</ul>
</div>
var $filters = $('.map__container .filters ul.tags li input[type=checkbox]').on('change', function() {
var $this = $(this),
tag = $this.data('tag'),
bounds = new google.maps.LatLngBounds(),
values = [];
$filters.each(function(i, elem) {
var value;
value = elem.checked && elem.value;
if (value) {
values.push(value);
}
});
var filterValue = values.join('|');
//console.log(filterValue);
$.each(map.markers, function (i, marker) {
if (marker.filter.type.indexOf(filterValue) > -1) {
marker.setVisible(true);
//console.log('true:' + marker.filter.type);
} else {
marker.setVisible(false);
//console.log('false:' + marker.filter.type);
}
});
});
var $filters = $('.map__container .filters ul.tags li input[type=checkbox]').on('change', function() {
var $this = $(this),
bounds = new google.maps.LatLngBounds(),
values = [];
$filters.each(function(i, elem) {
var value;
value = elem.checked && elem.value;
if (value) {
values.push(value);
}
});
var filterValue = values;
console.log(filterValue);
$.each(map.markers, function (i, marker) {
var tags = marker.filter.type.split("|");
$.each(tags, function(i, tag) {
if (filterValue.includes(tag)) {
marker.setVisible(true);
console.log('true:' + tag);
return false;
} else {
marker.setVisible(false);
console.log('false:' + tag);
}
});
});
});

Google Maps API Fetch Country Code

I'm using Google Autocomplete and would like to pull the Country Code (GB, IE, FR, etc... ) from the location entered on the site.
AutocompleteDirectionsHandler.prototype.setupPlaceChangedListener = function(autocomplete, mode) {
var me = this;
autocomplete.bindTo('bounds', this.map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (mode === 'ORIG') {
me.originPlaceId = place.place_id;
document.getElementById("orig_latitude").value= place.geometry.location.lat();
document.getElementById("orig_longitude").value= place.geometry.location.lng();
document.getElementById("country_from").value = place.address_components[1].short_name;
} else {
me.destinationPlaceId = place.place_id;
document.getElementById("dest_latitude").value= place.geometry.location.lat();
document.getElementById("dest_longitude").value= place.geometry.location.lng();
document.getElementById("country_to").value = place.address_components[2].short_name;
}
me.route();
});
};
Unfortunately here the
place.address_components[1].short_name;
is returning the local area where this city/town is located.
How can I get the country code?
Thank you all for your input on this matter, greatly appreciated ;-)
For more details see Place Autocomplete from google
Fiddle demo
JS Code:
var input = document.getElementById('searchTextField');
var options = {
types: ['geocode']
};
var autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
for (var i = 0; i < place.address_components.length; i += 1) {
var addressObj = place.address_components[i];
for (var j = 0; j < addressObj.types.length; j += 1) {
if (addressObj.types[j] === 'country') { /*outputs result if it is country*/
document.getElementById('country_shortName').innerHTML = addressObj.short_name
}
}
}
});
Html
<label for="searchTextField">Please Insert an address:</label>
<br>
<input id="searchTextField" type="text" size="50">
<p >Country Short Code: <span id="country_shortName"></span></p>
Thanks Deep 3015. I used your solution and it did work! Fantastic...
Note for other users who might bump into the same issue:
I had to replace .innerHTML with .value to make it work
Apart from that, working 100% now. Thanks again for your help [thumbs up]

Call markers based on radio button value

I am trying to call markers to a google map based on a value (year as a string). I thought by putting an on click event to listen for when the radio class is clicked, that I could initialize the $.getJSON and set the value for the year.
How can initialize the $.getJSON call when the radio button is clicked and base the variable yearValue on which radio button is checked?
Also, if I wanted to reset the markers each time a new radio button is clicked, would I need to put all of the markers in an array, set them to the map, then clear the array when a new radio button value is checked (say I choose 2014 instead of 2015?). How can I clear the markers when a new radio button is checked so that I don't see both years at the same time?
var map;
var mapProp;
var url = 'https://data.montgomerycountymd.gov/resource/5pue-gfbe.json?$limit=50000';
var count;
var marker;
var manyCategory = [];
var category = [];
var yearValue;
function initMap() {
mapProp = {
center: new google.maps.LatLng(39.154743, -77.240515),
zoom: 10
};
map = new google.maps.Map(document.getElementById('map'), mapProp);
}
function addInfoWindow(marker, message) {
var infoWindow = new google.maps.InfoWindow({
content: message
});
google.maps.event.addListener(marker, 'click', function() {
infoWindow.open(map, marker);
});
}
$(document).ready(function() {
if ($('input:radio[name="year"]').is("checked")) {
yearValue = $(this).val();
}
initMap();
$('.radioClass').on('click', function() {
$.getJSON(url, function(data) {
count = 0;
for (var i = 0; i < data.length; i++) {
var newDate = data[i].inspectiondate;
if (data[i].violation22 === "Out of Compliance" && newDate.slice(0, 4) === yearValue) {
if (data[i].hasOwnProperty('latitude')) {
count++;
var message = "<div>" + data[i].organization + "<br>" + (data[i].inspectiondate).slice(0, 10) + "</div>";
var uniqueIcon;
if (data[i].category === "Private School" || data[i].category === "Public School- Elementary" || data[i].category === "Public School- High" || data[i].category === "Public School- Middle") {
uniqueIcon = "https://maps.gstatic.com/mapfiles/ms2/micons/blue.png";
} else if (data[i].category === "Market" || data[i].category === "Carry Out" || data[i].category === "Snack Bar" || data[i].category === "Caterer" || data[i].category === "Restaurant") {
uniqueIcon = "https://maps.gstatic.com/mapfiles/ms2/micons/purple.png"
} else if (data[i].category === "Nursing Home" || data[i].category === "Hospital" || data[i].category === "Assisted Living") {
uniqueIcon = "https://maps.gstatic.com/mapfiles/ms2/micons/red.png"
} else {
uniqueIcon = "https://maps.gstatic.com/mapfiles/ms2/micons/yellow.png";
}
marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i].location.latitude, data[i].location.longitude),
title: "Hello, world. I received a food violation in 2015",
animation: google.maps.Animation.DROP,
icon: uniqueIcon,
});
marker.setMap(map);
//console.log(data[i].inspectionresults);
addInfoWindow(marker, message);
manyCategory.push(data[i].category);
}
}
}
//;
$.each(manyCategory, function(i, el) {
if ($.inArray(el, category) === -1) category.push(el);
})
//console.log(count);
//console.log(manyCategory);
//console.log(category);
});
});
});
h1,
#icons,
#radioDiv {
text-align: center;
}
#map {
margin: 0 auto;
width: 700px;
height: 400px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<h1>Rodent Violations</h1>
<div id="radioDiv">
<input type="radio" name="year" value="2015" class="radioClass">2015
<input type="radio" name="year" value="2014" class="radioClass">2014
</div>
<div id="icons">
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/blue.png">School
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/purple.png">Restaurant
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/red.png">Healthcare
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/yellow.png">All other
</div>
<div id="map"></div>
You need an array fo markers globally visibile that hold all the markers you create for let you clean them before you show the new markers.
var myMarkers
add the begin of the callback function clear the markers setting maps to null
$.getJSON(url, function(data) {
count = 0;
for (var i = 0; i < myMarkers.length; i++) {
myMarkers[i].setMap(null);
}
myMarkers = []; // empty the array
.......
popluate the myMArkers Array with all the marker you create
marker.setMap(map);
addInfoWindow(marker, message);
myMarkers.push(marker);

Manipulate google maps autocomplete results on dynamically loaded text fields

I have a page with an unknown number of ".city-name" text fields (generated dynamically).
I'm having issues working with the auto-complete results for these fields after they are generated. I think I'm not doing the right things with my loop.
http://jsfiddle.net/w0dwxg4a/
function getPlace_dynamic() {
var options = {types: ['(cities)']};
var inputs = document.getElementsByClassName('city-name');
for (i = 0; i < inputs.length; i++) {
var places = new google.maps.places.Autocomplete(inputs[i], options);
google.maps.event.addDomListener(inputs[i], 'keydown', function (e) {
if (e.keyCode == 13) {
e.preventDefault();
}
});
google.maps.event.addListener(places, 'place_changed', function () {
var results = places.getPlace();
var address_components = results.address_components;
var components = {};
jQuery.each(address_components, function (k, v1) {
jQuery.each(v1.types, function (k2, v2) {
components[v2] = v1.long_name;
});
});
$(inputs).val(components.locality + ", " + components.country);
$(inputs).closest("form").submit();
});
}
}
The desired behaviour for each".city-name" can be seen in the "#txtPlaces" JsFiddle. I need the box value to convert to "City, Country", and then submit once selected.
I have disabled the enter key because that was submitting the autocomplete without switching it over to "City, Country".
I got it using jQuery $.each: Seems to work.
var options = {
types: ['(cities)']
};
var input = document.getElementsByClassName('city-name');
$.each(input, function(i, x){
var this_id = input[i].id;
var this_input = document.getElementById(this_id);
var places = new google.maps.places.Autocomplete(input[i], options);
google.maps.event.addListener(places, 'place_changed', function () {
var results = places.getPlace();
var address_components = results.address_components;
var components = {};
jQuery.each(address_components, function (k, v1) {
jQuery.each(v1.types, function (k2, v2) {
components[v2] = v1.long_name;
});
});
$(this_input).val(components.locality + ", " + components.country);
$(this_input).closest("form").submit();
});
google.maps.event.addDomListener(input[i], 'keydown', function (e) {
if (e.keyCode == 13) {
e.preventDefault();
}
});
})
}