Last update on Wednesday, May 1st 2019

Using Leaflet and OpenStreetMap in an Ionic Application in one Go

OpenStreetMap is a great alternative to the Google Maps service.
In this tutorial, we will see how we can reproduce the same application we created in the Ionic Google Maps Native tutorial.

The restaurant mapping application will display some specific restaurants that will be placed on our map and another Page will display more info about them.

Our plan here is to:

  1. Load multiple markers on this map
  2. Handle events on those markers
  3. Transition to another area that contains a restaurant's information

We start by adding the Leaflet files.
For simplicity, in the index.html we add the CSS by using the unpkg website:

  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />

And the JavaScript through npm:

npm install leaflet

We can now add a map id to the home.page.ts file:

<ion-content>
  <div id="map" style="height:100%;"></div>
</ion-content>

We then import the plugins that we will need:

import { Component } from '@angular/core';
import { Platform } from '@ionic/angular';
import { Router } from '@angular/router';
import { Map, tileLayer, marker, icon } from 'leaflet';
import { Http } from '@angular/http';
import { map } from 'rxjs/operators';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  constructor(public http: Http,
              public plt: Platform,
              public router: Router) {}

The Http Angular Service and map operator will be used to get the restaurants information (position, name).

From the Leaflet plugin, we have:

  • Map: To create a new Leaflet Map
  • tileLayer: To load titleLayers from the OpenStreetMap service
  • marker: To create some markers on the map
  • icon: To give custom icons to a Leaflet marker

Now that we have everything we need, we can start by loading the information:

ngAfterViewInit() {
    this.plt.ready().then(() => {
      this.http.get('https://oghuxxw1e6.execute-api.us-east-1.amazonaws.com/dev')
      .pipe(map(res => res.json()))
      .subscribe(restaurants => this.initMap(restaurants));
    });
  }

We use the http Angular Service to access the data from Amazon then we get the json information and pass it to the following initMap method:

initMap(restaurants) {
    const map = new Map('map').setView([33.6396965, -84.4304574], 23);

    tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);

    const customMarkerIcon = icon({
      iconUrl: 'assets/images/custom-marker-icon.png',
      iconSize: [64, 64], 
      popupAnchor: [0, -20]
    });

    restaurants.forEach((restaurant) => {
      marker([restaurant.position.lat, restaurant.position.lgn], {icon: customMarkerIcon})
      .bindPopup(`<b>${restaurant.title}</b>`, { autoClose: false })
      .on('click', () => this.router.navigateByUrl('/restaurant'))
      .addTo(map).openPopup();
    });
  }

We start by creating the Leaftlet map by targetting the map id and setting the position and the zoom value.
The tileLayer is then loaded from the OpenStreetMap tile service.
As stated in the documentation, there are other options like {r} that will add "@2x" to the URL to load retina tiles and most tile servers require attribution.

This should be enough to display the map.
We can now create a new customMarkerIcon by passing the url where the icon is located and some positionning information.

The final part now, placing the restaurants and setting them properly.

For each restaurant, we create a new marker by setting the position and the icon that we want to use.
The bindPopup will add a popup with the restaurant's name and the autoClose property will allow us to have multiple popups opened at the same time.
We use the on event listener to specify that when a click is received, the Angular router will navigate to the restaurant page.
Finally we add the newly created marker to the map and open the popup.

We add a new route for the restaurant information:

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: './home/home.module#HomePageModule' },
  { path: 'restaurant', loadChildren: './restaurant/restaurant.module#RestaurantPageModule' }
];

In the restaurant.page.html, we only display that the restaurant is under construction:

<ion-header>
  <ion-toolbar>
    <ion-back-button></ion-back-button>
  </ion-toolbar>
</ion-header>

<ion-content text-center>
  <p> Hello this restaurant is under construction at the moment, come back later!</p>
  <img src="assets/images/under-construction.jpg">
</ion-content>

And Voila!

Ionic LeafLet OpenStreetMap Result

Implementing Native Google Maps in an Ionic Application

This tutorial will show you how to...

Implementing Google OAuth with AWS in Ionic

Learn how to mix together Google...

Introduction to Ionic Google Analytics

Learn how to track page views and...

Stay up to date


Join over 4000 other developers who already receive my tutorials and their source code out of the oven with other free JavaScript courses and an Angular cheatsheet!