Using Leaflet with Ionic 4

Vivek Singh Bisht
9 min readOct 1, 2019

When it comes to the question “Which API to use to load Maps for your Ionic application?” The general answer is to use Google Maps API. But google maps API is not free, well it’s almost free but you still need to add your credit card credentials to increase the quota of map load requests. What if you don’t have a credit card? Which API would you use then, to load ? One of the easiest ways of adding Maps to your application is by using Leaflet.

Leaflet is a JavaScript library which is built for adding interactive maps to our application. It works smoothly and efficiently in desktop platforms as well as in mobile platforms. The added advantage of using leaflet in our application is that it’s open-source.

We’re going to create a basic mobile application consisting of a form which requires us to fill in pickup location and the pickup location is going to be located using Leaflet.

This is how the application is going to look in your mobile phone after completion :

Homepage of the application
Home-Page of the Application
Pickup Location Page of the Application
Pickup Page of the Application

Requirements for our application :

  • node.js (For using npm)
  • Ionic (I’m using Ionic 4 for this application)
  • Angular (I’m using Angular 8 for this application)

Setting up our application :

Run the below commands in your command prompt/terminal to set up our application:

ionic start myApp blank
ionic generate page pickup-location

Now your project directory should look something like this :

Directory of the Application

Go to home/homepage.html, clear out all the starter code provided by ionic and replace it with the code below:

<ion-header>
<ion-toolbar>
<ion-title>
Access Location
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-item style="cursor: pointer;margin-top:100px;" (click)="onpickupClick()">
<ion-icon slot="start" name="locate"></ion-icon>
<ion-label position="stacked">Pickup Location</ion-label>
<ion-textarea style="margin-top:20px;" >{{pickupLocation}}</ion-textarea>
</ion-item>
</ion-content>

All we have done by writing this code is to create our home page which consists of a header in the form of a toolbar we called it Access Location.

Along with this we created a item element in the form of an input element but in this case instead of using <ion-input> i have used <ion-textarea>.

We have added a click event handler toour <ion-item> which calls a function “onpickupClick()” which is present in our component(don’t worry i’m going to show the component code right after this para). Along with this I have used interpolation to bind our component property “pickupLocation” to our view.

Now go to home/home.page.ts, replace your code with the code below so that your home.page.ts should look something like this :

import { Component } from '@angular/core';
import {Router} from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
pickupLocation: string;
constructor(private router:Router) {}
onpickupClick(){
this.router.navigate(['pickup-location']);
}

}

Here we have added our component property pickupLocation which will hold the value of our location. Function onpickupClick() will navigate our application to the pickup-location page. Make sure you have imported router from @angular/router.

If you run your code using “ionic serve” in your terminal right now, you are going to see the homepage appear with a Pickup Location text-label which is “clickable”. On clicking it, you will be navigated to Pickup-Location page.

Now we come to the interesting part where we finally add Leaflet maps to our application but before that, the code inside of your pickup-location page needs to be changed so go to pickup-location/pickup-location.page.html and replace it with the code below :

<ion-header>
<ion-toolbar>
<ion-button fill="clear" slot="start" (click)="goBack()">
<ion-icon name="arrow-back"></ion-icon>
</ion-button>
<ion-title>Pickup Location</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-item style="cursor: pointer" (click)="locatePosition()">
<ion-button fill="clear">
<ion-icon slot="start" name="map"></ion-icon>
Locate Position
</ion-button>
</ion-item>
<ion-item>
<ion-icon slot="start" name="locate"></ion-icon>
<ion-label position="stacked">Address</ion-label>
<ion-textarea [(ngModel)]="address" type="text" style="margin-top:20px;"></ion-textarea>
</ion-item>
<ion-button shape="round" expand="block" (click)="confirmPickupLocation()">Confirm Pickup Location</ion-button></ion-content>

Let’s quickly go through what we’ve added here. We’ve added a toolbar which reads Pickup Location and has a back button added which will help us go back to our homepage, this button has a “click” handler attached to it which executes goBack().

Along with this I have added another text-area with the label address and this text-area will have our address value loaded when we locate our position in the map. I’ve added two-way binding for this textarea using
[(ngModel)] and its value equals address which will be a component property.

And finally a button which executes confirmPickupLocation() on being clicked.

Now go to pickup-location/pickup-location.page.ts and replace the code inside it so that it looks something like this:

import { Component } from '@angular/core';@Component({
selector: 'app-pickup-location',
templateUrl: './pickup-location.page.html',
styleUrls: ['./pickup-location.page.scss'],
})
export class PickupLocationPage {
address:string[];
constructor() { }
}

Here as you can see I have added a property named address which will be bound to our view.

Now we need to add leaflet to our application, for adding leaflet in our application we need install leaflet using npm and also install @types/leaflet
So run the following commands in your command prompt/terminal:

npm install leaflet --save
npm install @types/leaflet

Alright we have installed Leaflet but how do we use it?
Here are the steps below to use leaflet :

  • Add Leaflet CSS file in the head section of index.html
  • Initialise a Leaflet Map using Leaflet objects in our component
  • Add tiles to the Leaflet Map

Let’s follow these steps,

Add the below link in the head section of index.html ( src/index.html) to add Leaflet CSS files :

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>

After adding Leaflet CSS files, go to pickup-location/pickup-location.page.ts and add the following import statements at the top of the page :

import {Map,tileLayer,marker} from 'leaflet';

Now we are ready to initialise our map, this is how leaflet maps are initialised :

new Map("map").setView([17.3850,78.4867], 13);

Now let’s go through the above command,
new Map() is used to initialise a new Map and it takes in a parameter which will be id of the DOM element in which the Map will be displayed.
setView() is used to set the view of map and it takes in two parameters, first parameter is an array of latitude and longitude and the second is the zoom level of the map.

We can rewrite the initialisation like this for better understanding :

new Map("id of the DOM element").setView([lat,long],zoomlevel);

I have set the latitude and longitude of Hyderabad you can change it to whatever area you like. The zoom level used here is 13 but again you can use the zoom-level according to your needs.

Next step is to add tiles to our map and it’s completely your choice from where you want to add tile-layer to your map in this project I have added tiles from openstreetmap.
We create the tile-layer like this :

tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{ attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'});

Now we need to add the tile layer to our map and also, add a div container with the id “mapId” inside pickup-location.page.html.

Add the following container inside <ion-content> of pickup-location/pickup-location.page.html :

<div id="mapId" style="height:200px"></div>

Add the code inside pickup-location/pickup-location.page.ts so that it looks like this :

import { Component } from '@angular/core';import {Map,tileLayer,marker} from 'leaflet';@Component({
selector: 'app-pickup-location',
templateUrl: './pickup-location.page.html',
styleUrls: ['./pickup-location.page.scss'],
})
export class PickupLocationPage {map:Map;
newMarker:any;
address:string[];
constructor(private router:Router) { }

// The below function is added
ionViewDidEnter(){
this.loadMap();
}
// The below function is added
loadMap(){
this.map = new Map("mapId").setView([17.3850,78.4867], 13);tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{ attribution: 'Map data © <a
href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors,
<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-
SA</a>'})
.addTo(this.map); // This line is added to add the Tile Layer to our map
}
goBack(){
this.router.navigate(["home"]);
}
}

Here as you can see I’ve added some code, let’s break it down,

I’ve added new properties map and newMarker, map is to store the initialised Map and newMarker is to add a marker to our Map.
Next, I’ve added a function IonViewDidEnter() which loads the map after the view of our application is initialised.
And finally loadMap() function which initialises our map and adds tile-layer to our Map.

If you run the code using “ionic serve”, you will see a map being loaded in the pickup-location page. Now we need to make the application locate us for that we need to add the following code inside the class PickupLocationPage in pickup-location/pickup-location.page.ts :

locatePosition(){
this.map.locate({setView:true}).on("locationfound", (e: any)=> {
this.newMarker = marker([e.latitude,e.longitude], {draggable:
true}).addTo(this.map);
this.newMarker.bindPopup("You are located here!").openPopup();

this.newMarker.on("dragend", ()=> {
const position = this.newMarker.getLatLng();
});
});
}

Let’s breakdown the code, if you look in the pickup-location.page.html, we have a <ion-item> which has a click event handler and is being handled by a function called locatePosition() and that is the function we’ve added above.

This function uses the locate method to locate you and on locating you, adds a marker to your map. To to this marker we’ve added a popup which says “You are located here”.

Next we have made our marker draggable which allows us to drag our marker and the latitudes and longitudes after the marker is dragged are stored in a constant.

If you run “ionic serve” now you’ll be able to see the complete working of our main functionality where we are able to locate our position in the map.

Next we’ll be converting the latitudes and longitudes that are available from the map and storing it into a component property and display it in the view.

For converting the latitudes and longitudes into a readable text we use nativegeocoder from ionic and the cordova plugin for it so run the code below to add geocoder in our application:

ionic cordova plugin add cordova-plugin-nativegeocoder
npm install @ionic-native/native-geocoder

Now add the code inside pickup-location.page.ts page so that it looks like this:

import {Component} from "@angular/core";
import { Router, NavigationExtras } from "@angular/router";
// The above import statement is added
import { Map, tileLayer, marker } from "leaflet";
import {NativeGeocoder,NativeGeocoderOptions} from "@ionic-native/native-geocoder/ngx";
// The above import statement is added
@Component({
selector: "app-pickup-location",
templateUrl: "./pickup-location.page.html",
styleUrls: ["./pickup-location.page.scss"]
})
export class PickupLocationPage {
map: Map;
newMarker: any;
address: string[];
constructor(private geocoder: NativeGeocoder, private router: Router) {}ionViewDidEnter() {
this.loadMap();
}
loadMap() {
this.map = new Map("mapId").setView([17.385, 78.4867], 13);
tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
}).addTo(this.map);
}
locatePosition() {
this.map.locate({ setView: true }).on("locationfound", (e: any) => {
this.newMarker = marker([e.latitude, e.longitude], {
draggable: true
}).addTo(this.map);
this.newMarker.bindPopup("You are located here!").openPopup();
this.getAddress(e.latitude, e.longitude); // This line is added

this.newMarker.on("dragend", () => {
const position = this.newMarker.getLatLng();
this.getAddress(position.lat, position.lng);// This line is added

});
});
}

//The function below is added
getAddress(lat: number, long: number) {
let options: NativeGeocoderOptions = {
useLocale: true,
maxResults: 5
};
this.geocoder.reverseGeocode(lat, long, options).then(results => {
this.address = Object.values(results[0]).reverse();

});
}
// The function below is added
confirmPickupLocation() {
let navigationextras: NavigationExtras = {
state: {
pickupLocation: this.address
}
};
this.router.navigate(["home"], navigationextras);
}
goBack() {
this.router.navigate(["home"]);
}
}

Let’s breakdown the code we added, we added a getAddress function which
uses the reversegeocode function and changes lat-long into readable text. To understand how the nativegeocoder works click here.

I’ve added the two lines of code inside the locateMap() function which invokes the getAddress function.

confirmPickupLocation() uses the navigationExtras in Angular to pass the property address to the other component. To understand how navigation extras work click here.

Finally in the home.page.ts add the code so that it looks like this :

import { Component } from '@angular/core';
import {Router,ActivatedRoute} from '@angular/router';
// activatedRoute is added to our above import statement
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
pickupLocation: string;

// The constructor below was changed
constructor(private router:Router,private route:ActivatedRoute) {
this.route.queryParams.subscribe(params =>{
if(this.router.getCurrentNavigation().extras.state){
this.pickupLocation = this.router.getCurrentNavigation().extras.state.pickupLocation;
}
});
}
onpickupClick(){
this.router.navigate(['pickup-location']);
}

}

I’ve added code inside the constructor so that it accesses the property we exported from pickup-location.page.ts (confirmPickupLocation()).

Now we are finally ready to run our application in mobile, for this you need to setup ionic for mobile platforms, here I have used android platform to run our application. For knowing how to set up your project for android platform click here.

After setting up android platform, run the below command to deploy it to your mobile which has been connected to your desktop/laptop through USB (Make sure you set the USB debugging to on in your mobile).

And there you go, we have created an IONIC 5 application and added Leaflet maps to it.

Originally published at http://mobiwebcoder.com.

--

--

Vivek Singh Bisht

Web and Mobile App Developer with passion to code for life.