🎞️

Working with Frameworks

🏡 Home 📖 Chapter 👉 Next
⚡  GMapsBook.com is crafted by Jozef Sorocin (🟢 Book a consulting hour) and powered by:
  • g-Xperts (Google Cloud & Business Profile Partner)
 

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 @Inputs and @Outputs. 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.”
Most artifacts like Markers, Polygons, and InfoWindows are supported out of the box.
While @agm/core does offer a wrapper around the ✏️Drawing library, @angular/google-maps does not.
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
⚠️
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>
app.component.html
@Component({
  ...
})
export class AppComponent {
  ...
	onMapInitialized(map: google.maps.Map) {
    console.info(map);
  }
}
app.component.ts

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;
  });
}

Already purchased? Sign in here.