Skip to content

Instantly share code, notes, and snippets.

@KeithNdhlovu
Last active July 20, 2017 08:35
Show Gist options
  • Save KeithNdhlovu/d1d9021a2c7f90ff25b30f4187051491 to your computer and use it in GitHub Desktop.
Save KeithNdhlovu/d1d9021a2c7f90ff25b30f4187051491 to your computer and use it in GitHub Desktop.
Angular JS Directives for Google map with place picker and on pin drag callback update position and Geocode address from location
<!-- [ You obviously need google maps] -->
<script type="text/javascript" src='https://maps.google.com/maps/api/js?key=[ "The secret key here" ]&libraries=places'></script>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#gmaps {
width: 100%;
height: 200px;
}
</style>
.....
<!-- How to use the place picker -->
<input id="address"
name="address"
type="text"
class="validate"
googleplace
on-place-changed="onPlaceChanged(placeDetails)"
class="validate">
.....
<!-- How to use the google map -->
<div googlemap ng-model="addressDetails"></div>
.....
<!-- The inputs for the position -->
<input id="latitude"
name="latitude"
ng-model="latitude"
ng-model-options="{ updateOn: 'blur' }"
ng-change="reverseGeoCode(latitude, longitude)"
type="text">
<input id="longitude"
name="longitude"
ng-model="longitude"
ng-model-options="{ updateOn: 'blur' }"
ng-change="reverseGeoCode(latitude, longitude)"
type="text">
.....
<script>
var app = angular.module('app', ['kevin.googlemap', 'kevin.googleplace']);
app.controller('sampeController', [$scope, function('scope') {
// Set the place details
$scope.addressDetails = {
lat: 200.22,
long: 200.00,
address: 'Some Awesome place'
};
// Since we also want to know what the address is if i just change the lat, long ... we need to listed for changes
// What to do when the place updates
$scope.onPlaceChanged = function(placeDetails) {
// console.log(placeDetails);
// udpate the address input and the lat / long inputs with new data
$scope.latitude = placeDetails.lat;
$scope.longitude = placeDetails.long;
$scope.address = placeDetails.address;
$scope.$broadcast('onPlaceChanged', placeDetails);
};
// We need to ask for geocoder to give us an address when the lat longs have been updated
$scope.reverseGeoCode = function(latitude, longitude) {
var position = {
lat: parseFloat(latitude),
long: parseFloat(longitude)
};
$scope.$broadcast('reverseGeo', position);
};
}];
</script>
angular.module('kevin.googlemap', [])
.directive('googlemap', function() {
// directive link function
var link = function(scope, element, attrs) {
var map, infoWindow;
var markers = [];
var geocoder = new google.maps.Geocoder;
// map config
var mapOptions = {
center: new google.maps.LatLng(scope.ngModel.lat, scope.ngModel.long),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: true
};
// init the map
function initMap() {
if (map === void 0) {
map = new google.maps.Map(element[0], mapOptions);
}
}
// place a marker
function setMarker(map, position, title, content, icon) {
var marker;
var markerOptions = {
position: position,
map: map,
title: title,
icon: icon,
draggable:true,
};
for (var i in markers) {
markers[i].setMap(null);
}
marker = new google.maps.Marker(markerOptions);
map.setCenter(position);
map.setZoom(17);
markers.push(marker); // add marker to array
google.maps.event.addListener(marker, 'dragend', function() {
var position = {
lat: parseFloat(marker.position.lat()),
long: parseFloat(marker.position.lng())
};
geocodeLatLng(geocoder, map, position);
});
updateAddressComponents(title, position)
}
function updateAddressComponents(title, position) {
// udpate address
$("#address").val(title);
$("#latitude").val(position.lat());
$("#longitude").val(position.lng());
};
function geocodeLatLng(geocoder, gMap, position) {
var latlng = {lat: position.lat, lng: position.long};
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === 'OK') {
if (results[0]) {
setMarker(map, new google.maps.LatLng(position.lat, position.long), results[0].formatted_address, '');
} else {
setMarker(map, new google.maps.LatLng(position.lat, position.long), 'Unknown address', '');
console.log('No results found for selected place');
}
} else {
setMarker(map, new google.maps.LatLng(position.lat, position.long), 'Unknown address', '');
console.warn('GEOCODE', 'No results found for selected place');
console.warn('GEOCODE-STATUS', status);
}
});
}
// We listen for changes on the input values, and then we prompt for geocode
scope.$on('reverseGeo', function (event, position) {
console.log("onReverseGeo", position);
geocodeLatLng(geocoder, map, position);
});
// When the place has changed
scope.$on('onPlaceChanged', function (event, placeDetails) {
console.log("onPlaceChanged", placeDetails);
setMarker(map, new google.maps.LatLng(placeDetails.lat, placeDetails.long), placeDetails.address, '');
});
// show the map and place some markers
initMap();
// Set the marker from the given values from the marker
setMarker(map, new google.maps.LatLng(scope.ngModel.lat, scope.ngModel.long), scope.ngModel.address, '');
};
return {
restrict: 'A',
template: '<div id="gmaps"></div>',
replace: true,
scope: {
ngModel: '=',
},
link: link
};
});
angular.module('kevin.goolgeplace', [])
.directive('googleplace', [ function() {
return {
scope: {
onPlaceChanged: '&'
},
link: function(scope, element, attrs, model) {
var options = {
};
scope.gPlace = new google.maps.places.Autocomplete(element[0], options);
google.maps.event.addListener(scope.gPlace, 'place_changed', function() {
var geoComponents = scope.gPlace.getPlace();
var latitude = geoComponents.geometry.location.lat();
var longitude = geoComponents.geometry.location.lng();
var addressComponents = {
lat: latitude,
long: longitude,
address: geoComponents.formatted_address
};
// Update map details
scope.onPlaceChanged({placeDetails: addressComponents});
// Update the value of address
$("#address").val(addressComponents.address);
});
}
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment