<!DOCTYPE html>
<html ng-app="locationApp">
<head>
<link rel="stylesheet" href="place-autocomplete.css" />
<link rel="stylesheet" href="//rawgit.com/angular/bower-material/master/angular-material.css" />
<script data-require="angular.js@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script data-require="angular-route.js@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular-route.js"></script>
<script data-require="angular-aria@1.4.0" data-semver="1.4.0" src="https://code.angularjs.org/1.4.0/angular-aria.js"></script>
<script data-require="angular-animate@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
<script src="//rawgit.com/angular/bower-material/master/angular-material.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<script src="app.js"></script>
<script src="home-ctrl.js"></script>
<script src="place-autocomplete.js"></script>
</head>
<body>
<ng-view></ng-view>
</body>
</html>
'use strict';
/**
* @ngdoc directive
* @name locationApp.directive:placeAutocomplete
* @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
*
* <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
*
* Usage:
* <place-autocomplete ng-model="selectedLocation"></place-autocomplete>
*
* 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(),
};
});
}
}
};
});
angular.module('locationApp', ['ngAnimate','ngMaterial', 'ngRoute'])
.config(function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'home.html',
controller: 'HomeCtrl'
}).
otherwise({
redirectTo: '/home'
});
});
<md-content>
<md-toolbar>
<div class="md-toolbar-tools">
<h2>
<span>Google places/location suggestions with md-autocomplete</span>
</h2>
<span flex></span>
</div>
</md-toolbar>
</md-content>
<md-content layout-padding>
<p>Start typing the name of a place/location below</p>
<div class="md-padding">
<place-autocomplete ng-model="location"></place-autocomplete>
<div ng-if="location.name">
<h4>Selected location</h4>
<pre>{{location|json}}</pre>
</div>
</div>
</md-content>
angular.module('locationApp')
.controller('HomeCtrl', function($scope) {
});
<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" md-floating-label="Location (place, city or region)">
<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>
/*
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;
}
}