Use Leaflet in your Angular 8 project for interactive maps

If you’re considering using interactive maps in your Angular application definitely Leaflet is a great choice. It’s open, easy to integrate with and has strong community support.

In my opinion, it’s the best alternative to the Google Maps. So, don’t lose the opportunity and check it yourself. I hope it will fit your needs.

Initialize the project

First of all, let’s create new Angular app using Angular CLI.

ng new angular-leaflet-starter --routing=false --style=scss

Now, let’s generate our main component – MapComponent.

cd angular-leaflet-starter
ng generate component map

Getting started with Leaflet

Using npm package manager install the Leaflet core library as well as ngx-leaflet which is the Leaflet package for the Angular. Additionally we’ll need TypeScript Leaflet typings.

npm install leaflet
npm install @asymmetrik/ngx-leaflet
npm install --save-dev @types/leaflet

Let’s configure Leaflet in out project.

Go to the angular.json and add a reference to Leaflet stylesheets in styles array.

...
"styles": [
              "src/styles.scss",
              "./node_modules/leaflet/dist/leaflet.css"
            ],
...
angular.json

Now it’s time to import LeafletModule into the AppModule (or the other module you’d like to use it).

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AppComponent} from './app.component';
import {LeafletModule} from '@asymmetrik/ngx-leaflet';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    LeafletModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}
app.module.ts

Let’s go into the component code, starting from HTML template.

Replace default text:

<p>map works!</p>
map.component.html

With div element where Leaflet map will be placed:

<div id="map"
     leaflet
     [leafletOptions]="mapOptions">
</div>
map.component.html

Let’s add some code to MapComponent stylesheets. We always have to specify the height for our map box.

#map {
  height: 600px;
}
map.component.scss

Okay, let’s go into MapComponent code and introduce MapOptions object the map will use to render.

Let’s take a look at the MapComponent code:

import {Component, OnInit} from '@angular/core';
import {latLng, MapOptions, tileLayer} from 'leaflet';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {

  mapOptions: MapOptions;

  constructor() {
  }

  ngOnInit() {
    this.initializeMapOptions();
  }

  private initializeMapOptions() {
    this.mapOptions = {
      center: latLng(51.505, 0),
      zoom: 12,
      layers: [
        tileLayer(
          'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
          {
            maxZoom: 18,
            attribution: 'Map data © OpenStreetMap contributors'
          })
      ],
    };
  }

}
map.component.ts

At this point you’re able to run the Angular app and see the map. If you simply need the plain map displayed it will be enough for you.

If you want to have an access to Map object for example to add new layers, markers or anything else, please follow the rest of this article.

Let’s introduce and initialize map variable and add a simple marker to the map. We need some modifications in our MapComponent code.

<div id="map"
     leaflet
     (leafletMapReady)="onMapReady($event)"
     [leafletOptions]="mapOptions">
</div>
map.component.html

As you can see leafletMapReady event listener has been introduced. It’s time to implement onMapReady method where we pass $event (in this case it’s a Leaflet Map object).

import {Component, OnInit} from '@angular/core';
import {latLng, MapOptions, tileLayer, Map, Marker, icon} from 'leaflet';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {

  map: Map;
  mapOptions: MapOptions;

  constructor() {
  }

  ngOnInit() {
    this.initializeMapOptions();
  }

  onMapReady(map: Map) {
    this.map = map;
    this.addSampleMarker();
  }

  private initializeMapOptions() {
    this.mapOptions = {
      center: latLng(51.505, 0),
      zoom: 12,
      layers: [
        tileLayer(
          'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
          {
            maxZoom: 18,
            attribution: 'Map data © OpenStreetMap contributors'
          })
      ],
    };
  }

  private addSampleMarker() {
    const marker = new Marker([51.51, 0])
      .setIcon(
        icon({
          iconSize: [25, 41],
          iconAnchor: [13, 41],
          iconUrl: 'assets/marker-icon.png'
        }));
    marker.addTo(this.map);
  }

}
map.component.ts

Leaflet assets usage

In order to use Leaflet assets such as marker-icon.png we mentioned in the code above it’s required to provide some config modifications.

Go back into the angular.json configuration file and modify it a little bit. Otherwise it won’t be possible to render the icon.

...
"assets": [
              "src/favicon.ico",
              "src/assets",
              {
                "glob": "**/*",
                "input": "./node_modules/leaflet/dist/images",
                "output": "assets/"
              }
            ]
...
angular.json

At this point it’s ready to go. Let’s test it.

Final results

Before running the project please replace auto-generated welcome page content in app.component.html with app-map component selector.

<app-map></app-map>
app.component.html

Okay, finally it’s time to run the app.

ng serve

Browse to http://localhost:4200 and you should see the final result.

As you can see the map with icon are ready to go.

So, that’s it for now. Stay tuned, soon I’ll deliver you more content regarding using Leaflet in Angular framework.

Good luck with Leaflet integration into your Angular application.

Hope it was useful for you. Let me know if you have any questions.

Resources

Leaflet documentation reference

ngx-leaflet repository

Leave a Reply

Your email address will not be published. Required fields are marked *