Skip to content

Instantly share code, notes, and snippets.

@vinaygopinath
Last active August 15, 2018 06:11
Show Gist options
  • Save vinaygopinath/49df0b58a276281e5ffa to your computer and use it in GitHub Desktop.
Save vinaygopinath/49df0b58a276281e5ffa to your computer and use it in GitHub Desktop.
Google maps location/place suggestions with Angular material autocomplete (md-autocomplete) https://plnkr.co/edit/dITwTF?p=preview
/*
Optional adjustments for md-autocomplete in mobile screens
*/
#place-autocomplete > md-autocomplete md-input-container {
margin-top: -10px;
}
/*Media query for tablets and above */
@media screen and (min-width: 480px) {
#place-autocomplete > md-autocomplete md-input-container {
padding-bottom: 0;
}
}
<div id="place-autocomplete">
<md-autocomplete md-no-cache="false" md-selected-item="location" md-selected-item-change="getLatLng(item)" ng-model-options="{debounce: 600}" md-search-text-change="search(searchText)" md-search-text="searchText" md-items="item in search(searchText)"
md-item-text="item.description" md-min-length="2" md-max-length="50" placeholder="Type your address" md-floating-label="Location (area and city)">
<md-item-template>
<span md-highlight-text="searchText" md-highlight-flags="^i">{{item.description}}</span>
</md-item-template>
<md-not-found>
No matches found for "{{searchText.description}}".
</md-not-found>
</md-autocomplete>
</div>
'use strict';
/**
* @ngdoc directive
* @name locationApp.directive:placeAutocomplete
* @author Vinay Gopinath
* @description
*
* # An element directive that provides a dropdown of
* location suggestions based on the search string.
* When an item is selected, the location's latitude
* and longitude are determined.
*
* This directive depends on the Google Maps API
* with the places library, i.e,
* <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
*
* @example
* <place-autocomplete ng-model="selectedLocation"></place-autocomplete>
*
* Demo:
* http://plnkr.co/edit/dITwTF?p=preview
*
* Credit:
* http://stackoverflow.com/a/31510437/293847
*/
angular.module('locationApp')
.directive('placeAutocomplete', function() {
return {
templateUrl: 'place-autocomplete.html',
restrict: 'E',
replace: true,
scope: {
'ngModel': '='
},
controller: function($scope, $q) {
if (!google || !google.maps) {
throw new Error('Google Maps JS library is not loaded!');
} else if (!google.maps.places) {
throw new Error('Google Maps JS library does not have the Places module');
}
var autocompleteService = new google.maps.places.AutocompleteService();
var map = new google.maps.Map(document.createElement('div'));
var placeService = new google.maps.places.PlacesService(map);
$scope.ngModel = {};
/**
* @ngdoc function
* @name getResults
* @description
*
* Helper function that accepts an input string
* and fetches the relevant location suggestions
*
* This wraps the Google Places Autocomplete Api
* in a promise.
*
* Refer: https://developers.google.com/maps/documentation/javascript/places-autocomplete#place_autocomplete_service
*/
var getResults = function(address) {
var deferred = $q.defer();
autocompleteService.getQueryPredictions({
input: address
}, function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
/**
* @ngdoc function
* @name getDetails
* @description
* Helper function that accepts a place and fetches
* more information about the place. This is necessary
* to determine the latitude and longitude of the place.
*
* This wraps the Google Places Details Api in a promise.
*
* Refer: https://developers.google.com/maps/documentation/javascript/places#place_details_requests
*/
var getDetails = function(place) {
var deferred = $q.defer();
placeService.getDetails({
'placeId': place.place_id
}, function(details) {
deferred.resolve(details);
});
return deferred.promise;
};
$scope.search = function(input) {
if (!input) {
return;
}
return getResults(input).then(function(places) {
return places;
});
};
/**
* @ngdoc function
* @name getLatLng
* @description
* Updates the scope ngModel variable with details of the selected place.
* The latitude, longitude and name of the place are made available.
*
* This function is called every time a location is selected from among
* the suggestions.
*/
$scope.getLatLng = function(place) {
if (!place) {
$scope.ngModel = {};
return;
}
getDetails(place).then(function(details) {
$scope.ngModel = {
'name': place.description,
'latitude': details.geometry.location.lat(),
'longitude': details.geometry.location.lng(),
};
});
}
}
};
});
@arunchauhan73
Copy link

Hi VinayGopinath,
Good work!
But when I am using multiple autocomplete in search form so here I am not able to change their placeholder, md-input-id etc.
What should I do to resolve this?
How can we change this element directive to attribute directive and can use in md-autocomplete?

@farhadkzm
Copy link

Thanks dude, helped me a lot 👍

@mrst
Copy link

mrst commented Sep 6, 2017

Uuuuh, just what I was searching for! Thanks too man!

@jperez1804
Copy link

Hi, how can you pass a value to init the autocomplete? I mean, i am in an edit window and i want to pass the inital latitude lingitude to be set when the form renders, thanks in advance

@o5man
Copy link

o5man commented Apr 8, 2018

Hi, great gist - thank you! 👍

If anyone has problems with minification of this: you need to change the controller definition in line 36 to :

controller: ['$scope', '$q', function($scope, $q) {

and close the square brackets again in line 123. Maybe it helps someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment