The pearl-lullaby (v9.0.0-rc.0) introduces the second official @angular/component
component, a Google Maps component. In this post, we take a look at getting started with the Google Maps component.
Earlier this year, we changed the name of this repo to “angular/components” to emphasize our goal to provide more than Material Design components. The 9.0.0 release includes one of the next new features in that regard- a new package that wraps the Google Maps JavaScript API in an easy-to-use Angular component.
I’m really looking forward to the team broadening up the repository to create components. We already saw a YouTube Player component in v8.2.0, which is explored in Craig’s article.
These new integrations with existing JavaScript APIs are making it easier for us to do our jobs, and I’m curious about the other new components that will be released in the upcoming versions!
Angular
The Google Maps module can be installed from @angular/google-maps
.
npm install @angular/google-maps
When the installation is finished, we must add the Angular module GoogleMapsModule
to the import
declaration.
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { GoogleMapsModule } from '@angular/google-maps'
import { AppComponent } from './app.component'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, GoogleMapsModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
appmodule.ts
The GoogleMapsModule
exports three components that we can use:
GoogleMap
: this is the wrapper around Google Maps, available via the google-map
selectorMapMarker
: used to add markers on the map, available via the map-marker
selectorMapInfoWindow
: the info window of a marker, available via the map-info-window
selectorLoading the Maps JavaScript API
We also have to import the Maps API, this can be done by adding a script tag in the index.html
file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Map</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
index.html
To use the map in a production environment you will need to create a new API Key, follow the documentation to create a new key.
GoogleMap
By adding the Google Maps component to a template we can already see and use the Google Map. The map will behave as a default map with the default functionality, for example, you can zoom in and out, and drag in the map.
<google-map></google-map>
app.html
A default of Google Map
Input properties
We can customize the styling of the default map by using the @Input()
properties. The most commonly used properties are added as @Input
properties, we can set the size of the map, set the center, and set the zoom level.
To make full use of the Google Maps API, we can also use the options
property. Using the explicit properties wins over using the options
property. The options
property has the same has the interface as the Map Options interface.
export class AppComponent implements OnInit {
zoom = 12
center: google.maps.LatLngLiteral
options: google.maps.MapOptions = {
mapTypeId: 'hybrid',
zoomControl: false,
scrollwheel: false,
disableDoubleClickZoom: true,
maxZoom: 15,
minZoom: 8,
}
ngOnInit() {
navigator.geolocation.getCurrentPosition(position => {
this.center = {
lat: position.coords.latitude,
lng: position.coords.longitude,
}
})
}
zoomIn() {
if (this.zoom < this.options.maxZoom) this.zoom++
}
zoomOut() {
if (this.zoom > this.options.minZoom) this.zoom--
}
}
app.ts
A styled Google Map
Output properties
The GoogleMap
component exposes all the Google Maps API events as @Output()
properties:
Covering all of these events would be a lot for one post, in this post we’ll go over the click()
event. If you’re interested in all the events I refer you to the Google Maps API Docs for the complete list, and the Angular implementation in the source code.
<google-map (mapClick)="click($event)"></google-map>
app.html
export class AppComponent implements OnInit {
click(event: google.maps.MouseEvent) {
console.log(event)
}
}
app.ts
Methods and getters
If we keep a reference to the map component, by using the @ViewChild decorator, we can also use the following methods and getters.
As an example, we can log the current center of the map.
export class AppComponent implements OnInit {
@ViewChild(MapInfoWindow, { static: false }) info: MapInfoWindow
logCenter() {
console.log(JSON.stringify(this.map.getCenter()))
}
}
app.ts
Input properties
With the map in place, we can start adding markers. This is done by using the MapMarker
component. To add a marker, make sure the marker is added inside the google-map
tag otherwise it will not be displayed.
Just like the MapControl
, the most frequently used options can be set directly with @Input()
properties, but it’s also possible to make use of the full options set of the MapMarker.
<google-map>
<map-marker
*ngFor="let marker of markers"
[position]="marker.position"
[label]="marker.label"
[title]="marker.title"
[options]="marker.options"
>
</map-marker>
</google-map>
app.html
export class AppComponent implements OnInit {
addMarker() {
this.markers.push({
position: {
lat: this.center.lat + ((Math.random() - 0.5) * 2) / 10,
lng: this.center.lng + ((Math.random() - 0.5) * 2) / 10,
},
label: {
color: 'red',
text: 'Marker label ' + (this.markers.length + 1),
},
title: 'Marker title ' + (this.markers.length + 1),
options: { animation: google.maps.Animation.BOUNCE },
})
}
}
app.ts
A Google Map with markers
The full specification of the marker:
Output properties
The MapMarker
component also exposes the Google Maps API events as @Output()
properties:
The full reference to the API can be found at the Google Maps API Docs, and the Angular implementation in the source code.
The last component is MapInfoWindow
, it can be used to open a pop-up window of a marker. To show the pop-up we have to add the component inside the google-map
template.
<map-info-window>Hello Google Maps</map-info-window>
app.html
The above does nothing, to make it appear we have to open the info window when we click on a marker. We bind the mapClick()
method to the marker and pass the marker reference to the openInfo
method to open the info window.
<map-marker
#markerElem
*ngFor="let marker of markers"
[position]="marker.position"
[label]="marker.label"
[title]="marker.title"
[options]="marker.options"
(mapClick)="openInfo(markerElem)"
>
</map-marker>
app.html
Finally, we also have to add a reference to theMapInfoWindow
component inside our component, we can do this by using the @ViewChild decorator. By having the reference to the info window and the marker, we can open the info window by using the infoWindow.open()
method.
export class AppComponent implements OnInit {
@ViewChild(MapInfoWindow, { static: false }) infoWindow: MapInfoWindow
openInfo(marker: MapMarker, content) {
this.infoWindow.open(marker)
}
}
app.ts
Input properties
Output properties
Methods and getters
By using the infoWindow
property, that has a reference to the MapInfoWindow
component we can make use of its following methods and getters:
Dynamic content
Having static content inside the info window is a bit dull. To provide dynamic content inside the info window, we can create a string property within the component, this looks as follows.
<map-info-window>{{ infoContent }}</map-info-window>
app.html
export class AppComponent implements OnInit {
@ViewChild(MapInfoWindow, { static: false }) infoWindow: MapInfoWindow
infoContent = ''
openInfo(marker: MapMarker, content) {
this.infoContent = content
this.infoWindow.open(marker)
}
}
app.ts
The full reference to the API can be found at the Google Maps API Docs, and the Angular implementation in the source code.
The upcoming version of Angular brings us a whole range of positive changes and new possibilities. We were already looking forward to the Ivy release in Angular v9, but now we’ll also look forward to the new release of @angular/components
.
Besides the new MapComponent
there will also be an integration with the Clipboard API within the Angular CDK, as explored in Use the new Angular Clipboard CDK to interact with the clipboard.
The Angular component is very new, that’s why the documentation and example code is minimal. Because the Angular implementation follows the Google Maps API specs, we can take a look at the rich documentation from the JavaScript API.
See the code below for the full explored example of this post.
<google-map
height="500px"
width="100%"
[zoom]="zoom"
[center]="center"
[options]="options"
(mapClick)="click($event)"
>
<map-marker
#markerElem
*ngFor="let marker of markers"
[position]="marker.position"
[label]="marker.label"
[title]="marker.title"
[options]="marker.options"
(mapClick)="openInfo(markerElem, marker.info)"
>
</map-marker>
<map-info-window>{{ infoContent }}</map-info-window>
</google-map>
<button (click)="zoomIn()">Zoom in</button>
<button (click)="zoomOut()">Zoom out</button>
<button (click)="logCenter()">Log center</button>
<button (click)="addMarker()">Add marker</button>
app.html
import { Component, OnInit, ViewChild } from '@angular/core'
import { MapInfoWindow, MapMarker, GoogleMap } from '@angular/google-maps'
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
@ViewChild(GoogleMap, { static: false }) map: GoogleMap
@ViewChild(MapInfoWindow, { static: false }) info: MapInfoWindow
zoom = 12
center: google.maps.LatLngLiteral
options: google.maps.MapOptions = {
zoomControl: false,
scrollwheel: false,
disableDoubleClickZoom: true,
mapTypeId: 'hybrid',
maxZoom: 15,
minZoom: 8,
}
markers = []
infoContent = ''
ngOnInit() {
navigator.geolocation.getCurrentPosition(position => {
this.center = {
lat: position.coords.latitude,
lng: position.coords.longitude,
}
})
}
zoomIn() {
if (this.zoom < this.options.maxZoom) this.zoom++
}
zoomOut() {
if (this.zoom > this.options.minZoom) this.zoom--
}
click(event: google.maps.MouseEvent) {
console.log(event)
}
logCenter() {
console.log(JSON.stringify(this.map.getCenter()))
}
addMarker() {
this.markers.push({
position: {
lat: this.center.lat + ((Math.random() - 0.5) * 2) / 10,
lng: this.center.lng + ((Math.random() - 0.5) * 2) / 10,
},
label: {
color: 'red',
text: 'Marker label ' + (this.markers.length + 1),
},
title: 'Marker title ' + (this.markers.length + 1),
info: 'Marker info ' + (this.markers.length + 1),
options: {
animation: google.maps.Animation.BOUNCE,
},
})
}
openInfo(marker: MapMarker, content) {
this.infoContent = content
this.info.open(marker)
}
}
app.ts
#angular #javascript #programming