Google Maps and Street View in Angular: from an address to a working view

Show an address on a map, open Street View, and add a “Use my location” button. A step-by-step Angular walkthrough with practical code examples.

Illustration of a location pin on a folded city map transitioning into an interactive street panorama.
From an address on a map to a street-level view.

On a project I worked on, we wanted a quick way to see the area around an address without leaving the page. A small button opened Street View in a modal—no copying the address into another tab.

The flow is straightforward:

Address → coordinates → Street View

Let’s build a simple Angular version, then add a map and an optional “Use my location” button.

1. Prepare your Google Maps key

In Google Cloud, create or select a project, configure billing, and enable Maps JavaScript API and Geocoding API. Create an API key with website restrictions for your development and production origins, then limit it to the APIs you use.

A browser key is visible to visitors. Restrictions protect it; moving it into an Angular environment file does not hide it. Check current pricing, set suitable quotas, and add billing alerts. Alerts alone do not cap spending. See Google’s security guide.

2. Load the API when needed

Install the loader and TypeScript definitions:

npm install @googlemaps/js-api-loader@^2
npm install --save-dev @types/google.maps

Create maps-loader.ts. Configure this once; do not add a second Maps script to index.html.

import { setOptions, importLibrary } from '@googlemaps/js-api-loader';

setOptions({ key: 'YOUR_RESTRICTED_BROWSER_KEY', v: 'weekly' });

export async function loadMaps() {
  await Promise.all([
    importLibrary('maps'),
    importLibrary('geocoding'),
    importLibrary('streetView')
  ]);
}

This uses the v2 loader API. The placeholder is intentional—use your own restricted key.

3. Give the map somewhere to live

Create a standalone component. Its template, address-view.component.html, needs two containers with a real height:

<button (click)="openAddress()" [disabled]="busy()">Show address</button>
<button (click)="useMyLocation()" [disabled]="busy()">Use my location</button>
<p role="status">{{ message() }}</p>
<div #mapCanvas style="height: 240px"></div>
<div #streetCanvas style="height: 420px"></div>

An empty-looking map is sometimes just a container with no height. Start here before debugging your key.

4. Connect the address, map and panorama

Use this in address-view.component.ts. The sample address is a public museum, not a customer record.

import { Component, ElementRef, OnDestroy, ViewChild, signal } from '@angular/core';
import { loadMaps } from './maps-loader';

@Component({
  selector: 'app-address-view',
  standalone: true,
  templateUrl: './address-view.component.html'
})
export class AddressViewComponent implements OnDestroy {
  @ViewChild('mapCanvas') mapCanvas!: ElementRef<HTMLElement>;
  @ViewChild('streetCanvas') streetCanvas!: ElementRef<HTMLElement>;
  busy = signal(false);
  message = signal('Choose an address or use your location.');
  private map?: google.maps.Map;
  private panorama?: google.maps.StreetViewPanorama;
  private destroyed = false;

  async openAddress() {
    if (this.busy()) return;
    this.busy.set(true);
    this.message.set('Finding address…');
    try {
      await loadMaps();
      const { results } = await new google.maps.Geocoder().geocode({
        address: 'Rijksmuseum, Museumstraat 1, Amsterdam, Netherlands'
      });
      const result = results[0];
      if (!result) throw new Error('No address result');
      await this.show(result.geometry.location.toJSON());
    } catch {
      this.message.set('Could not find this address. Check it and try again.');
    } finally {
      this.busy.set(false);
    }
  }

  private async show(position: google.maps.LatLngLiteral) {
    if (this.destroyed) return;
    this.map ??= new google.maps.Map(this.mapCanvas.nativeElement, {
      center: position, zoom: 17, streetViewControl: false
    });
    this.map.setCenter(position);
    this.panorama?.setVisible(false);

    try {
      const { data } = await new google.maps.StreetViewService().getPanorama({
        location: position, radius: 50,
        preference: google.maps.StreetViewPreference.NEAREST,
        source: google.maps.StreetViewSource.OUTDOOR
      });
      if (this.destroyed) return;
      if (!data.location?.pano) throw new Error('No panorama');
      this.panorama ??= new google.maps.StreetViewPanorama(
        this.streetCanvas.nativeElement,
        { pov: { heading: 0, pitch: 0 }, zoom: 1 }
      );
      this.panorama.setPano(data.location.pano);
      this.panorama.setVisible(true);
      this.message.set('Nearby Street View. It may not face the exact entrance.');
    } catch {
      this.message.set('Map loaded. No Street View could be loaded nearby.');
    }
  }

  // Add useMyLocation() from the next step here.

  ngOnDestroy() {
    this.destroyed = true;
    this.panorama?.setVisible(false);
    if (this.panorama) google.maps.event.clearInstanceListeners(this.panorama);
    if (this.map) google.maps.event.clearInstanceListeners(this.map);
  }
}

Import this standalone component into its parent and render <app-address-view />. In a modal, create it after opening and keep both containers mounted while loading. For an SSR application, keep browser API work in browser-triggered handlers, as above.

The important extra check is getPanorama(): finding an address does not guarantee nearby imagery. The map stays useful even if Street View fails. See Google’s geocoding and Street View guides.

5. Optional: use the device location

Geocoding finds an address. Browser geolocation asks where the current device is. Add this method inside the component above:

async useMyLocation() {
  if (this.busy()) return;
  if (!navigator.geolocation) {
    this.message.set('Location is not supported in this browser.');
    return;
  }
  this.busy.set(true);
  this.message.set('Waiting for location permission…');
  try {
    const location = await new Promise<GeolocationPosition>((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(resolve, reject, {
        timeout: 10000, maximumAge: 60000, enableHighAccuracy: false
      });
    });
    if (this.destroyed) return;
    await loadMaps();
    await this.show({
      lat: location.coords.latitude,
      lng: location.coords.longitude
    });
  } catch {
    this.message.set('Location unavailable. You can still use the address.');
  } finally {
    this.busy.set(false);
  }
}

Request it after a click. Browser geolocation requires a secure context and permission; accuracy varies. Tell users that choosing this feature sends their coordinates to Google to display the area. See MDN’s geolocation reference.

A few checks before shipping

  • Address not found: include the house number, postcode, city and country. Let users correct ambiguous results.
  • Map works, Street View does not: coverage and the requested search radius matter.
  • API error: check enabled APIs, key restrictions, billing and the browser console.
  • Modal closed while loading: ignore late results and release listeners.

Keep the loading state clear, make failures understandable, and leave the original address easy to reach. The feature should feel like a natural part of the page.

Share this article

Facebook LinkedIn WhatsApp X

For Instagram or another app, copy the link or use More options when available.

Bujar Ademi

Written by

Bujar Ademi

Senior .NET Developer & Team Lead

← All articles