Brian F Love
Learn from a Google Developer Expert focused on Angular, Web Technologies, and Node.js from Portland, OR.
Learn Angular the right way with Ultimate Courses

Angular 2 + Google Maps Places Autocomplete

In this brief tutorial I'll show you to to quickly build an Angular 2 + Google Maps Places Autocomplete application.

The Places Autocomplete by Google Maps is very helpful as it allows a user to search for an address or specific location. I'll combine the Places Autocomplete API with a Google Map using the Angular Google Maps (agm) module.


Check out the Plunker:

Getting Started

The first thing to do is to install the Angulage Google Maps module as well as the Google Maps TypeScript declarations file using Node Package Manager (npm):

$ npm install @agm/core --save
$ npm install @types/googlemaps --save-dev

Next, modify your @NgModule decorator:

import { AgmCoreModule } from '@agm/core';

  imports: [
      apiKey: "YOUR KEY GOES HERE",
      libraries: ["places"]
  declarations: [ App ],
  bootstrap: [ App ]
export class AppModule() {}

To review the code above:

  • First, we import the AgmCoreModule class from the @agm/core module.
  • In our the imports property we use the AgmCoreModule.forRoot() method and specify the places library.
  • You will notice that I am also using ReactiveFormsModule for Angular's new model-driven forms.

Create Template

For this tutorial I am going to set the styles and template properties in my @Component decorator configuration. I would suggest that you have an external Sass file and an external HTML template instead. Let's take a look at the @Component configuration:

  selector: 'my-app',
  styles: [`
    agm-map {
      height: 300px;
  template: `
    <div class="container">
      <h1>Angular 2 + Google Maps Places Autocomplete</h1>
      <div class="form-group">
        <input placeholder="search for location" autocorrect="off" autocapitalize="off" spellcheck="off" type="text" class="form-control" #search [formControl]="searchControl">
      <agm-map [latitude]="latitude" [longitude]="longitude" [scrollwheel]="false" [zoom]="zoom">
        <agm-marker [latitude]="latitude" [longitude]="longitude"></agm-marker>
export class App implements OnInit {}

A couple of things to note:

  • Don't forget that you must define a height for the map element. In this case, I am setting it to 300px.
  • For the template, I am using some minimal Bootstrap CSS styling to make things look nice.
  • My input element uses a local template variable named search. This is declared using the hash symbol ( # ), or I could have used the ref- prefix such as ref-search.
  • My input element has one-way data binding for the FormControl directive to the searchControl publicly available variable in my controller. We'll look at this in a moment.
  • Next, I am implementing the agm-map directive as per the documentation for the Angular Google Maps module. I am binding the latitude to a public variable in my controller named latitude, and I am doing the same thing for the longitude. I am also setting the scrollwheel option to false. Then I bind the zoom value to my zoom property in my controller.
  • I have also included a marker that will use the same longitude and latitude as the center point for the map.

Implement Controller

Next, we need to implement our controller. Let's take a look at it:

import { ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import { } from 'googlemaps';
import { MapsAPILoader } from '@agm/core';

export class App implements OnInit {

  public latitude: number;
  public longitude: number;
  public searchControl: FormControl;
  public zoom: number;

  public searchElementRef: ElementRef;

    private mapsAPILoader: MapsAPILoader,
    private ngZone: NgZone
  ) {}

  ngOnInit() {
    //set google maps defaults
    this.zoom = 4;
    this.latitude = 39.8282;
    this.longitude = -98.5795;

    //create search FormControl
    this.searchControl = new FormControl();

    //set current position

    //load Places Autocomplete
    this.mapsAPILoader.load().then(() => {
      let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement, {
        types: ["address"]
      autocomplete.addListener("place_changed", () => { => {
          //get the place result
          let place: google.maps.places.PlaceResult = autocomplete.getPlace();

          //verify result
          if (place.geometry === undefined || place.geometry === null) {

          //set latitude, longitude and zoom
          this.latitude =;
          this.longitude = place.geometry.location.lng();
          this.zoom = 12;

  private setCurrentPosition() {
    if ("geolocation" in navigator) {
      navigator.geolocation.getCurrentPosition((position) => {
        this.latitude = position.coords.latitude;
        this.longitude = position.coords.longitude;
        this.zoom = 12;

First, I import the necessary classes: NgZone, OnInit, ViewChild, FormControl and MapsAPILoader.

Inside the class we first define our public variables to store the latitude, longitude, zoom and our searchControl. Next, I am using the @ViewChild decorator to get access to the DOM input element. The @ViewChild decorator accepts a single string that is the selector to the element or directive. In this case I am referencing the local template variable #search. It decorates the variable searchElementRef, which is an ElementRef to the search input.

Next, I use dependency injection (DI) to inject the MapsAPILoader and NgZone dependencies. We'll use the MapsAPILoader later on in the ngOnInit() method to load the Google Places API. The NgZone service enables us to perform asynchronous operations outside of the Angular zone, or in our case, to explicitly run a function within the Angular zone. Angular's zones patch most of the asynchronous APIs in the browser, invoking change detection when an asynchronous code is completed. As you might expect Angular zones are not patching the asynchronous behavior of Google Place autocomplete.

Now, in the ngOnInit() method I set some initial values for the latitude, longitude and zoom. Then, I create a new FormControl() instance for the searchControl. Next I invoke the setCurrentPosition() method, which will simply attempt to use the geolocation API in the browser to set the map to the user's current location. You can just ignore this if you want.

I then use the load() method in the MapsAPILoader to load the Google Places API. This returns a promise object, so when this has been resolved we can then fire up our Google Places Autocomplete. The code here should look familiar to the code sample available from Google.

Note: I am limiting the results for Google Places Autocomplete to addresses using the types option. If you want to show all results, simply remove this, or specify an alternative type.

Finally, we use the fat arrow function in TypeScript to attach an event handler to the placechanged_ event for our autocomplete. We then wrap our asynchronous code within the method.

The documentation for NgZone indicates that:

Running functions via run allows you to reenter Angular zone from a task that was executed outside of the Angular zone

Within the run() method we will store the data returns from the Google Maps Places API, including updating our map's latitude and longitude. Without the use of the method the changes to our latitude, longitude and zoom will not be triggered until change detection is triggered by another event or asynchronous operation.


Here is a demo on Plunker:

Brian F Love

Hi, I'm Brian. I am interested in TypeScript, Angular and Node.js. I'm married to my best friend Bonnie, I live in Portland and I ski (a lot).