⚡ GMapsBook.com is crafted by Jozef Sorocin (🟢 Book a consulting hour) and powered by:
- g-Xperts (Google Cloud & Business Profile Partner)
- Spatialized.io (Elasticsearch & Google Maps consulting).
- and Garages-Near-Me.com (Effortless parking across Germany)
Status QuoGoogle Maps with AngularYour optionsThe official @angular/google-maps libraryInstallation & Typescript typesInputs & OutputsAccessing the map instanceComponents of componentsFull Angular 16 DemoGoogle Maps with ReactYour optionsThe @react-google-maps libraryInstallation & Typescript typesA reusable wrapperAccessing the map instanceCustom native markersCustom DOM markersFull React 18 Demo
Status Quo
To be approachable to a wide range of developers, this handbook purposefully contains vanilla Javascript/Typescript code snippets.
After all, around 40% of all websites still run on Wordpress where Javascript only gets sprinkled here and there.
And in the Javascript ecosystem, your favorite libraries/frameworks like React, Angular, Vue, or Svelte come nowhere close in widespread usage to good old jQuery and Boostrap.
Admittedly, the Javascript framework ecosystem is a bit of a mess. To make some sense of it, check out Fireship’s videos on this topic.
Still, if you’re developing a larger app, you will likely reach for a Javascript framework like Angular or a meta-framework like Next.js to ship faster and write more maintainable code.
In this chapter you’ll learn how Google Maps client libraries for Angular and React can help abstract away some “vanilla Google Maps” verbosity and peculiarities. In the end, the client libraries should improve your developer experience and boost your implementation confidence.
Google Maps with Angular
Your options
There are practically two libraries to choose from —
@agm/core
and @angular/google-maps
.@agm/core
, developed by Sebastian Holstein, is very popular but no longer maintained.@angular/google-maps
is developed by the official Angular team and has better support and maintenance.Both libraries wrap around the Javascript Google Maps API via components and expose their bindings via
@Input
s and @Output
s. Instead of manually creating Javascript instances via new google.maps.XYZ()
, you will conveniently import the respective modules and interact with them in “idiomatic Angular.”It’s also worth noting that neither package implements the StreetView API — there’s an open PR for
@angular/google-maps
though.That said, let’s look at a typical Angular implementation of Google Maps.
The official @angular/google-maps
library
Installation & Typescript types
In your Angular project (e.g. this stackblitz boilerplate), run:
npm install @angular/google-maps
as a dependency and then:
npm install --save-dev @types/google.maps
as a dev dependency.
Note that
@types/googlemaps
is deprecated in favor of @types/google.maps
.Then, in your
tsconfig.json
, make sure to include the .d.ts
declarations provided by the @types
typings:{
...
"include": ["src/**/*.d.ts"]
}
Your Typescript compiler might still complain about:
Cannot find namespace 'google'.
You can bypass this warning by explicitly referencing the
@types
package on the first line of your app.component.ts
or main.ts
:/// <reference types="@types/google.maps" />
Once these configurations are through, it’s time for the fun part.
Inputs & Outputs
In your
app.component.html
, insert the <google-maps>
tag:<google-map width="100%" height="100%" [options]="opts">
</google-map>
and in
app.component.ts
, declare the options
:/// <reference types="@types/google.maps" />
import { Component } from '@angular/core';
import { GoogleMap } from '@angular/google-maps';
@Component({
selector: 'app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
opts: google.maps.MapOptions = {
zoom: 10,
gestureHandling: 'greedy',
center: {
lat: 40.7419,
lng: -73.9921,
},
controlSize: 24,
mapId: '7e3c1737b205d71e',
};
}
Any changes to
opts
will now automatically reflect on the map without having to manually trigger .setOptions()
.Now,
@angular/google-maps
doesn’t have a dedicated documentation site so you must consult GitHub or your IDE to inspect the available inputs and outputs. For instance, to be notified when the map loads for the first time, there’s the (mapInitialized)
output:<google-map
...
(mapInitialized)="onMapInitialized($event)"
>
</google-map>
@Component({
...
})
export class AppComponent {
...
onMapInitialized(map: google.maps.Map) {
console.info(map);
}
}
Accessing the map instance
Speaking of accessing the map instance… You can safely get hold of the
google.maps.Map
instance by:- either listening to events/outputs that emit said instance
- or by using
@ViewChild
:
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { GoogleMap } from '@angular/google-maps';
@Component({
...
})
export class AppComponent implements AfterViewInit {
@ViewChild(GoogleMap) map: GoogleMap;
...
ngAfterViewInit() {
console.info(this.map);
}
}
this.map
now refers to the ViewChild
wrapper of your Google Map. To access the “native” instance, use this.map.googleMap
. To learn more about console.info
and related Dev Tools Console commands, read 6. Tips & Tricks.Components of components
Angular is built around the concepts of clearly separated components. The
@angular/google-maps
library is no different.To display a list of restaurants (as seen in Custom Marker Labels), create a
RestaurantsComponent
and add it to your root module.After that, specify an array of restaurants in
restaurants.component.ts
and loop over the array to construct an array of google.maps.MarkerOptions
:import { Component } from '@angular/core';
import { encodeSVG, generateSvgMarkup } from './svg';
@Component({
selector: 'app-restaurants',
templateUrl: './restaurants.component.html',
})
export class RestaurantsComponent {
private restaurants = [
{
position: {
lat: 40.7419,
lng: -73.9921,
},
numOfPositions: 12,
},
...
];
markers = this.restaurants.map((r) => {
return {
position: r.position,
icon: {
url: encodeSVG(generateSvgMarkup(r.numOfPositions)),
scaledSize: new google.maps.Size(42, 45),
anchor: new google.maps.Point(17, 45),
},
} as google.maps.MarkerOptions;
});
}