var app = angular.module('plunker', ['vsGoogleAutocomplete']);
app.controller('MainCtrl', function($scope) {
$scope.options = {
componentRestrictions: { country: 'MX' }
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>vsHandyStorage Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link data-require="bootstrap-css" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.2.x" src="https://code.angularjs.org/1.2.28/angular.js" data-semver="1.2.28"></script>
<!-- Google Maps JavaScript API -->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<!-- vsGoogleAutocomplete -->
<script src="vs-google-autocomplete.js"></script>
<script src="app.js"></script>
</head>
<!--
* Dependency: Google Maps JavaScript API v3
* Google Maps API info: https://developers.google.com/maps/documentation/javascript/places-autocomplete
* Usage:
* 1. add <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
* 2. add vs-google-autocomplete.js
* 3. add vs-google-autocomplete directive to input field
-->
<body ng-controller="MainCtrl">
<div class="container">
<h3>Example of vsGoogleAutocomplete module</h3>
<h5>Also look at <a href="http://plnkr.co/edit/u91e8N?p=preview">example</a> of a autocomplete validation through embedded validator</h5>
<form>
<!-- vs-google-autocomplete -->
<div class="form-group">
<label for="place">Place</label>
<input vs-google-autocomplete
ng-model="place"
type="text"
name="place"
id="place"
class="form-control"
placeholder="Enter any address">
<span class="help-block"><b>Model: </b>{{place}}</span>
</div>
<!-- vs-google-autocomplete="{ types:['(cities)'] }" -->
<div class="form-group">
<label for="city">City</label>
<input vs-google-autocomplete="{ types:['(cities)'] }"
ng-model="city"
type="text"
name="city"
id="city"
class="form-control"
placeholder="Enter city name">
<span class="help-block"><b>Model: </b>{{city}}</span>
</div>
<!-- vs-google-autocomplete="options" -->
<div class="form-group">
<label for="city">City of France</label>
<input vs-google-autocomplete="options"
ng-model="cityFR"
type="text"
name="cityFR"
id="cityFR"
class="form-control"
placeholder="Enter city name of France">
<span class="help-block"><b>Model: </b>{{cityFR}}</span>
</div>
<!-- parsing address components -->
<div class="form-group">
<label for="address">Address</label>
<span>(parsing address components example)</span>
<input vs-google-autocomplete
ng-model="address.name"
vs-place="address.place"
type="text"
name="address"
id="address"
class="form-control"
placeholder="Enter address">
{{ address.place.address_components[3].long_name }}
<span class="help-block"><b>Model: </b>{{address.name}}</span>
<span class="help-block"><b>Place id: </b>{{address.components.placeId}}</span>
<span class="help-block"><b>Street number: </b>{{address.components.streetNumber}}</span>
<span class="help-block"><b>Street: </b>{{address.components.street}}</span>
<span class="help-block"><b>City: </b>{{address.components.city}}</span>
<span class="help-block"><b>State: </b>{{address.components.state}}</span>
<span class="help-block"><b>Country code: </b>{{address.components.countryCode}}</span>
<span class="help-block"><b>Country: </b>{{address.components.country}}</span>
<span class="help-block"><b>Postcode: </b>{{address.components.postCode}}</span>
<span class="help-block"><b>District: </b>{{address.components.district}}</span>
<span class="help-block"><b>Latitude: </b>{{address.components.location.lat}}</span>
<span class="help-block"><b>Longitude: </b>{{address.components.location.long}}</span>
<span class="help-block"><b>Longitude: </b>{{address.components.location.long}}</span>
<pre class="help-block"><b>Place: </b>{{address.place | json}}</pre>
</div>
</form>
</div>
</body>
</html>
/**
* vsGoogleAutocomplete - v0.5.0 - 2015-11-29
* https://github.com/vskosp/vsGoogleAutocomplete
* Copyright (c) 2015 K.Polishchuk
* License: MIT
*/
(function (window, document) {
'use strict';
angular.module('vsGoogleAutocomplete', []);
angular.module('vsGoogleAutocomplete').service('vsGooglePlaceUtility', function() {
function isGooglePlace(place) {
if (!place)
return false;
return !!place.place_id;
}
function isContainTypes(place, types) {
var placeTypes,
placeType,
type;
if (!isGooglePlace(place))
return false;
placeTypes = place.types;
for (var i = 0; i < types.length; i++) {
type = types[i];
for (var j = 0; j < placeTypes.length; j++) {
placeType = placeTypes[j];
if (placeType === type) {
return true;
}
}
}
return false;
}
function getAddrComponent(place, componentTemplate) {
var result;
if (!isGooglePlace(place))
return;
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentTemplate[addressType]) {
result = place.address_components[i][componentTemplate[addressType]];
return result;
}
}
return;
}
function getPlaceId(place) {
if (!isGooglePlace(place))
return;
return place.place_id;
}
function getStreetNumber(place) {
var COMPONENT_TEMPLATE = { street_number: 'short_name' },
streetNumber = getAddrComponent(place, COMPONENT_TEMPLATE);
return streetNumber;
}
function getStreet(place) {
var COMPONENT_TEMPLATE = { route: 'long_name' },
street = getAddrComponent(place, COMPONENT_TEMPLATE);
return street;
}
function getCity(place) {
var COMPONENT_TEMPLATE = { locality: 'long_name' },
city = getAddrComponent(place, COMPONENT_TEMPLATE);
return city;
}
function getState(place) {
var COMPONENT_TEMPLATE = { administrative_area_level_1: 'short_name' },
state = getAddrComponent(place, COMPONENT_TEMPLATE);
return state;
}
function getDistrict(place) {
var COMPONENT_TEMPLATE = { administrative_area_level_2: 'short_name' },
state = getAddrComponent(place, COMPONENT_TEMPLATE);
return state;
}
function getCountryShort(place) {
var COMPONENT_TEMPLATE = { country: 'short_name' },
countryShort = getAddrComponent(place, COMPONENT_TEMPLATE);
return countryShort;
}
function getCountry(place) {
var COMPONENT_TEMPLATE = { country: 'long_name' },
country = getAddrComponent(place, COMPONENT_TEMPLATE);
return country;
}
function getPostCode(place) {
var COMPONENT_TEMPLATE = { postal_code: 'long_name' },
postCode = getAddrComponent(place, COMPONENT_TEMPLATE);
return postCode;
}
function isGeometryExist(place) {
return angular.isObject(place) && angular.isObject(place.geometry);
}
function getLatitude(place) {
if (!isGeometryExist(place)) return;
return place.geometry.location.lat();
}
function getLongitude(place) {
if (!isGeometryExist(place)) return;
return place.geometry.location.lng();
}
return {
isGooglePlace: isGooglePlace,
isContainTypes: isContainTypes,
getPlaceId: getPlaceId,
getStreetNumber: getStreetNumber,
getStreet: getStreet,
getCity: getCity,
getState: getState,
getCountryShort: getCountryShort,
getCountry: getCountry,
getLatitude: getLatitude,
getLongitude: getLongitude,
getPostCode: getPostCode,
getDistrict: getDistrict
};
});
angular.module('vsGoogleAutocomplete').directive('vsGoogleAutocomplete', ['vsGooglePlaceUtility', '$timeout', function(vsGooglePlaceUtility, $timeout) {
return {
restrict: 'A',
require: ['vsGoogleAutocomplete', 'ngModel'],
scope: {
vsGoogleAutocomplete: '=',
vsPlace: '=?',
vsPlaceId: '=?',
vsStreetNumber: '=?',
vsStreet: '=?',
vsCity: '=?',
vsState: '=?',
vsCountryShort: '=?',
vsCountry: '=?',
vsPostCode: '=?',
vsLatitude: '=?',
vsLongitude: '=?',
vsDistrict: '=?'
},
controller: ['$scope', '$attrs', function($scope, $attrs) {
this.isolatedScope = $scope;
/**
* Updates address components associated with scope model.
* @param {google.maps.places.PlaceResult} place PlaceResult object
*/
this.updatePlaceComponents = function(place) {
$scope.vsPlaceId = !!$attrs.vsPlaceId && place ? vsGooglePlaceUtility.getPlaceId(place) : undefined;
$scope.vsStreetNumber = !!$attrs.vsStreetNumber && place ? vsGooglePlaceUtility.getStreetNumber(place) : undefined;
$scope.vsStreet = !!$attrs.vsStreet && place ? vsGooglePlaceUtility.getStreet(place) : undefined;
$scope.vsCity = !!$attrs.vsCity && place ? vsGooglePlaceUtility.getCity(place) : undefined;
$scope.vsPostCode = !!$attrs.vsPostCode && place ? vsGooglePlaceUtility.getPostCode(place) : undefined;
$scope.vsState = !!$attrs.vsState && place ? vsGooglePlaceUtility.getState(place) : undefined;
$scope.vsCountryShort = !!$attrs.vsCountryShort && place ? vsGooglePlaceUtility.getCountryShort(place) : undefined;
$scope.vsCountry = !!$attrs.vsCountry && place ? vsGooglePlaceUtility.getCountry(place) : undefined;
$scope.vsLatitude = !!$attrs.vsLatitude && place ? vsGooglePlaceUtility.getLatitude(place) : undefined;
$scope.vsLongitude = !!$attrs.vsLongitude && place ? vsGooglePlaceUtility.getLongitude(place) : undefined;
$scope.vsDistrict = !!$attrs.vsDistrict && place ? vsGooglePlaceUtility.getDistrict(place) : undefined;
};
}],
link: function(scope, element, attrs, ctrls) {
// controllers
var autocompleteCtrl = ctrls[0],
modelCtrl = ctrls[1];
// google.maps.places.Autocomplete instance (support google.maps.places.AutocompleteOptions)
var autocompleteOptions = scope.vsGoogleAutocomplete || {},
autocomplete = new google.maps.places.Autocomplete(element[0], autocompleteOptions);
// google place object
var place;
// value for updating view
var viewValue;
// updates view value and address components on place_changed google api event
google.maps.event.addListener(autocomplete, 'place_changed', function() {
place = autocomplete.getPlace();
viewValue = place.formatted_address || modelCtrl.$viewValue;
scope.$apply(function() {
scope.vsPlace = place;
autocompleteCtrl.updatePlaceComponents(place);
modelCtrl.$setViewValue(viewValue);
modelCtrl.$render();
});
});
// updates view value on focusout
element.on('blur', function(event) {
viewValue = (place && place.formatted_address) ? viewValue : modelCtrl.$viewValue;
$timeout(function() {
scope.$apply(function() {
modelCtrl.$setViewValue(viewValue);
modelCtrl.$render();
});
});
});
// prevent submitting form on enter
google.maps.event.addDomListener(element[0], 'keydown', function(e) {
if (e.keyCode == 13) {
e.preventDefault();
}
});
}
};
}]);
})(window, document);