Compatible from Angular 2 to latest version 9
Angular Google Maps package provides fully featured integration of Javascript-based Google Maps in Angular Applications.
Here we will discuss how to:
- Install Google Maps and Add API Keys
- Add Dynamic Google Maps in a Component
- Add Location Search Filter
- Draggable Marker
- Zoom Control
- Get Lattitude and Longitude of Marker Placed
Check the working demo here.
There’s a lot to do 🙂 Let’s get started!
Install Packages
First, we need to install some required packages.
Angular Google Maps Package
To use Google Maps in Angular project, install AGM package by running following NPM command
$ npm install @agm/core --save
GoogleMaps types library
For using Google Maps search feature we need to declare google variable for that install @types/googlemaps
by running following NPM command
$ npm install @types/googlemaps --save-dev
Bootstrap Framework
User can open a modal which will have Google Maps to select a location by using search or marker dragging feature.
To install Bootstrap in Angular project run following NPM command
@ npm install --save @ng-bootstrap/ng-bootstrap
Also, include bootstrap.css in index.html to use bootstrap stylings
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
So here we have successfully installed the required packages, next, we need to import them in App Module.
Create Google Maps Component
In modal, we will show Google maps which in turn will be a separate component. Run the following generate
command to create a new component.
$ ng generate component components/google-maps
Configurations
In the app.module.ts file, we need to import AgmCoreModule
for Google Maps and NgbModule
for Bootstrap. After that add them in imports array as shown below:
// app.module.ts ... import { GoogleMapsComponent } from './components/google-maps/google-maps.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { AgmCoreModule } from '@agm/core'; @NgModule({ declarations: [ AppComponent, GoogleMapsComponent// <- Component to show in modal ], imports: [ BrowserModule, AppRoutingModule, NgbModule, AgmCoreModule.forRoot({ apiKey: 'AIzaSyAzSnhHOwXXXXXXXXXXXXXmhZSZGGWU', libraries: ['places'] }) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Add GoogleMaps type in the tsconfig.app.json file at the project root. In the "types" array add
"googlemaps"
as shown below:
... "compilerOptions": { "outDir": "./out-tsc/app", "types": [ "googlemaps" ] }, ...
Open Google Maps Modal
In the App component we will now add a button to open a bootstrap modal by calling openGoogelMapsModal()
method.
<div class="text-center"> <p> <button class="btn btn-primary" (click)="openGoogelMapsModal()">Open Google Map</button> </p> <h1> <p *ngIf="coordinates.address"> Address: {{coordinates.address}} </p> </h1> <h3> <p *ngIf="coordinates.latitude"> Latitude: {{coordinates.latitude}} </p> <p *ngIf="coordinates.longitude"> Longitude: {{coordinates.longitude}} </p> </h3> </div>
Using modal a user can select a coordinate with address where marker is placed.
After saving the location the coordinates and address will be returned and assigned to the coordinates object with following properties:
interface Coordinates {
address: string;
latitude: number;
longitude: number;
}
The app.component.ts file will have following code to open the Bootstrap Modal
// app.component.ts import { Component } from '@angular/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { GoogleMapsComponent } from './components/google-maps/google-maps.component'; interface Coordinates { address: string; latitude: number; longitude: number; } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'angular-google-maps-demo'; coordinates: Coordinates; constructor( private modalService: NgbModal ) { this.coordinates = {} as Coordinates; } openGoogelMapsModal() { const modalRef = this.modalService.open(GoogleMapsComponent, { scrollable: true, // windowClass: 'myCustomModalClass', // keyboard: false, // backdrop: 'static' }); let data = { prop1: 'Some Data', prop2: 'From Parent Component', prop3: 'This Can be anything' } modalRef.componentInstance.fromParent = data; modalRef.result.then((result) => { this.coordinates = result; }, (reason) => { }); } }
To use modal, import NgbModal
service to call its the open
method where we passed GoogleMapsComponent
which we created earlier. Optional data
can be passed in modal using data object.
Adding Google Maps with Draggable marker and Search for Places
To show a map, add the agm-map
with [latitude]
, [longitude]
and [zoom]
properties for default location.
For draggable marker add agm-marker
wrapped in agm-map
.
We will also add an input field to search places with #search
template variable to control search events and bind places result set.
Place the final HTML template in google-maps.component.html file
<div class="modal-header">
<h3 class="modal-title">Angular Google Maps with Places Search Example</h3>
<button type="button" class="close" data-dismiss="modal" (click)="closeModal('dismiss')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" class="form-control" (keydown.enter)="$event.preventDefault()"
placeholder="Search Nearest Location" autocorrect="off" autocapitalize="off" spellcheck="off" type="text"
#search>
</div>
<agm-map [latitude]="latitude" [longitude]="longitude" [zoom]="zoom">
<agm-marker [latitude]="latitude" [longitude]="longitude" [markerDraggable]="true"
(dragEnd)="markerDragEnd($event)"></agm-marker>
</agm-map>
<h5>Address: {{address}}</h5>
<div>Latitude: {{latitude}}</div>
<div>Longitude: {{longitude}}</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="closeModal('close')">Close</button>
<button type="button" class="btn btn-primary" (click)="saveLocation()">Save Location</button>
</div>
Note: Please add following css in styles.css file to autocomplete search results on modal.
.pac-container{
z-index: 9999;
}
Now update the GoogleMapsComponent
 with Autocomplete places search method which will be called when Modal is initialized.
The MapsAPILoader
service imported from @agm/core
will call the load
method when maps are ready. The setCurrentLocation()
will get current latitude and longitude using navigator
‘s geolocation service.
The markerDragEnd()
method is called when marker is dragged manually by user to fetch coordinates to call getAddress()
method fetching address using the Geocoder
service.
The saveLocation
method will pass current selection of coordinates and address in the NgbActiveModal
‘s close to pass them on App component’s results callback.
The final code for google.maps.component.ts file will look like this:
// google-maps.component.ts
import { Component, OnInit, ViewChild, ElementRef, NgZone, Input } from '@angular/core';
import { MapsAPILoader } from '@agm/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-google-maps',
templateUrl: './google-maps.component.html',
styleUrls: ['./google-maps.component.scss']
})
export class GoogleMapsComponent implements OnInit {
title: string = 'AGM project';
latitude: number;
longitude: number;
zoom: number;
address: string;
private geoCoder;
@ViewChild('search')
public searchElementRef: ElementRef;
@Input() fromParent;
constructor(
private mapsAPILoader: MapsAPILoader,
private ngZone: NgZone,
public activeModal: NgbActiveModal
) { }
ngOnInit() {
//load Places Autocomplete
this.mapsAPILoader.load().then(() => {
this.setCurrentLocation();
this.geoCoder = new google.maps.Geocoder;
let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
autocomplete.addListener("place_changed", () => {
this.ngZone.run(() => {
//get the place result
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
//verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
//set latitude, longitude and zoom
this.latitude = place.geometry.location.lat();
this.longitude = place.geometry.location.lng();
this.zoom = 12;
});
});
});
}
// Get Current Location Coordinates
private setCurrentLocation() {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
this.zoom = 8;
this.getAddress(this.latitude, this.longitude);
});
}
}
markerDragEnd($event: any) {
console.log($event);
this.latitude = $event.coords.lat;
this.longitude = $event.coords.lng;
this.getAddress(this.latitude, this.longitude);
}
getAddress(latitude, longitude) {
this.geoCoder.geocode({ 'location': { lat: latitude, lng: longitude } }, (results, status) => {
console.log(results);
console.log(status);
if (status === 'OK') {
if (results[0]) {
this.zoom = 12;
this.address = results[0].formatted_address;
} else {
window.alert('No results found');
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
});
}
closeModal(sendData) {
this.activeModal.close(sendData);
}
saveLocation(){
const data = {
address: this.address,
latitude: this.latitude,
longitude: this.longitude
}
this.activeModal.close(data);
}
}
Also check :
Angular 13 Google Maps Integration with Markers, Info Windows Tutorial
That’s it now you have Google Map component to get location inputs from user from any parent component.
Leave a Reply