Setting Up Leaflet
Begin by installing the Leaflet package and configuring it in the angular.json file so the library is loaded.
npm install leaflet
Open angular.json and include the leaflet.css and leaflet.js files as assets.
"styles": [
"src/styles.css",
"node_modules/leaflet/dist/leaflet.css"
],
"scripts": [
"node_modules/leaflet/dist/leaflet.js"
]
},
"configurations": { ...
Defining the Leaflet API Contract
To work with the methods exposed by Leaflet, it is helpful to define an interface that describes the public API of the global object. While optional, this practice makes the code more readable and maintainable.
export interface LeafletAPI {
map(id:string):object;
setView(points: [], id:number): object;
tileLayer(url:string, options:object): object;
addTo(map:object):void;
}
Creating the InjectionToken
Import the InjectionToken class from @angular/core. This class allows you to create a new token instance based on the LeafletAPI interface. The global object is accessed by its string name — in this case, the Leaflet global is L.
import { InjectionToken} from '@angular/core';
export let LEAFLET_TOKEN = new InjectionToken<LeafletAPI>('L');
Registering the Provider
In the AppModule, define a variable that references the L global. Then, register the LEAFLET_TOKEN in the providers array and set its useValue to the L variable.
With this setup, Angular will return the L instance whenever the LEAFLET_TOKEN is requested for injection.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { LealefAPI, LEALEF_TOKEN } from './services/lealef.injector';
declare let L: LealefAPI;
@NgModule({
declarations: [
AppComponent
],
imports: [BrowserModule],
providers: [
{ provide: LEALEF_TOKEN, useValue: L}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Injecting with @Inject
The @Inject() decorator tells Angular which object to inject. By using the token as the key, the dependency injector resolves the value that was declared in the providers for that token.
In this example, the key is LEAFLET_TOKEN. Angular retrieves it from the registered provider and constructs a new MapService. Inside the constructor, the leaflet field is declared with @Inject and the token.
import { Inject, Injectable } from '@angular/core';
import { LeafletAPI, LEAFLET_TOKEN } from './lealef.injector';
@Injectable()
export class MapService {
constructor(@Inject(LEAFLET_TOKEN) private _leaflet: LealefAPI) { }
The dependency injector successfully injects Leaflet into MapService, and the methods from LeafletAPI are now available for use.
@Injectable()
export class MapService {
constructor(@Inject(LEAFLET_TOKEN) private _leaflet: LealefAPI) { }
showMenorca(): void {
let map = this._leaflef.map('mapid').setView([39.9255, 4.032], 13);
const tiles = this._leaflef.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
maxZoom: 8,
minZoom: 3
}
);
tiles.addTo(map);
}
}
}
Wrapping Up
This approach helps avoid relying directly on global objects by leveraging InjectionToken and @Inject. If this was useful, feel free to share it.
Photo by Fernando @cferdo on Unsplash
