Using Angular 2 to import an external Leaflet library written in TypeScript

Seeking help in integrating a TypeScript Leaflet library into my Angular 2 application.

Below is my map component. I have successfully installed leaflet.d.ts using tsd install and there are no complaints about

/// <reference path="../../typings/leaflet/leaflet.d.ts"/>
. However, when trying to utilize an exported module L.map from leaflet.d.ts, I encounter the error "ReferenceError: L is not defined". This is my first attempt at importing an external TypeScript library into Angular 2, so clearly there's something amiss.

/// <reference path="../../typings/leaflet/leaflet.d.ts"/>
import { Component } from 'angular2/core';
@Component({
  selector: 'map',
  template: `
        <div id="map"></div>
  `,
})
export class Map{
    constructor(){
          var map = new L.Map('map', {
             zoomControl: false
         });
    }

package.json

{
  "dependencies": {
    "angular2": "^2.0.0-beta.3",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "normalize.css": "^3.0.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "systemjs": "0.19.6",
    "typings": "^0.6.4",
    "zone.js": "^0.5.11"
  },
  "devDependencies": {
    "concurrently": "^1.0.0",
    "gh-pages": "^0.11.0",
    "grunt": "~0.4.5",
    "grunt-contrib-clean": "^1.0.0",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-cssmin": "^1.0.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-sass": "~0.9.0",
    "grunt-contrib-uglify": "~0.5.0",
    "grunt-shell": "^1.2.1",
    "lite-server": "^2.0.1",
    "normalize.css": "^3.0.3",
    "typescript": "^1.7.5"
  },
  "scripts": {
    "publish": "node publish.js",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "lite": "lite-server",
    "start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
  }
}

tsd.json

{
  "version": "v4",
  "repo": "borisyankov/DefinitelyTyped",
  "ref": "master",
  "path": "typings",
  "bundle": "typings/tsd.d.ts",
  "installed": {
    "leaflet/leaflet.d.ts": {
      "commit": "1da639a106527e0c4010b354a1efe52a3059a291"
    }
  }
}

Would appreciate any insights on what might be going wrong here.

Thank you!

Answer №1

It is important to ensure that you have included the leaflet JS file:

System.config({
  map: {
    leaflet: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js'
  },
  packages: {'app': {defaultExtension: 'ts'}} 
});
System.import('app/main')
        .then(null, console.error.bind(console));

To use it in your modules, you can import it like this:

import {Component, OnInit} from 'angular2/core';
import leaflet from 'leaflet';

You can also refer to this plunkr example for further guidance: http://plnkr.co/edit/aUo2uvlxC5ji32u01jfF?p=preview.

Answer №2

Here is a helpful workaround for using 3rd party libraries with angular-cli until better support is available. It worked wonders for me :)

To start, navigate to your project directory and enter the following command:

npm install leaflet --save

Next, open your angular-cli-build.js file and include this line:

vendorNpmFiles: [
   ..................
   'leaflet/**/*.js',
    ....................
  ]

Now, modify your src/system-config.ts as follows:

const map:any ={
     ..................
   'leaflet': 'vendor/leaflet/dist',
    ....................

}

And add the packages configuration:

const packages: any = {
  'leaflet': {
    format: 'cjs'
  }

};

In your src/index.html file, insert the script tag:

<script type="text/javascript" src="vendor/leaflet/dist/leaflet.js"></script>

Don't forget to link the CSS file as well:

<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />

Finally, in the component where you want to use Leaflet:

declare let L: any;
@Component({
  moduleId: module.id,
  selector: 'app-map',
  templateUrl: 'map.component.html',
  styleUrls: ['map.component.css']
})
export class MapComponent implements OnInit, AfterViewInit {
 leafletMap: any;
 ngAfterViewInit() {
    this.leafletMap = L.map("map").setView([23.709921, 90.407143], 7);
 }
}

Voila! Your map should now be successfully loaded :D

Answer №3

To successfully implement Thierry Templier's solution with systemjs and Angular 2.4, I made some necessary adjustments.

Following his instructions, I included Leaflet in my system.config.js file. However, to ensure its functionality in my component, I had to import it as shown below:

import * as L from 'leaflet';

After doing so, the L class was properly recognized in my MapComponent

export class MapComponent {
    let map = L.map("map").setView([38, -77], 13);
            L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            }).addTo(map);
    }

Answer №4

While you're at it, make sure to check out all the necessary steps that need to be taken

npm install @types/leaflet@latest --save

and don't forget to add the source in index.html.

No additional imports or declarations are required. The import statement could then resemble

import {control, LatLng, layerGroup, LayerGroup, Map} from "leaflet";

Remember, map initialization should occur within ngOnInit(), constructor usage is not meant for logic.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Discovering Child Elements in Angular 2 with @ViewChild and CSS Selectors

I'm looking to update the style of the second paragraph using either the nth-child() selector or by a specific class: import { Component, ViewChild } from '@angular/core'; @Component({ selector: 'my-app', template: ` <d ...

Creating a user login with email and password using AngularFire2 requires following a few specific steps to successfully

I successfully created a login-service that allows users to log in with Google, Facebook, or Twitter. However, I am facing some difficulties while trying to implement the option for logging in with an email and password (this feature is enabled in the Fire ...

Module not found in Typescript

Filter.ts, mustache.js and redux.3.5.2.js are all located in the same directory (/Scripts). The code snippet within Filter.ts is as follows: ///<reference path="./typings/mustache.d.ts" /> import Mustache = require("mustache"); import Redux = requir ...

The soft keyboard on Android devices may be obscured by an input field when using Cordova

When I use the text input field on my Android phone, the soft keyboard covers the input field. My app is built with Cordova and Angular 6. I have attempted the following solution: <preference name="Fullscreen" value="false" /> <edit-config file ...

Angular - Javascript - Oops! The variable 'google' seems to have gone missing after reloading the page

For my website, I utilized Angular 2+ and integrated the Google Maps Api by adding the following code to my index.html file: <script async defer src="//maps.googleapis.com/maps/api/js?[myKey]&libraries=places"> </script> ...

Importing an anonymous ES5 function using Typescript

I am currently facing an issue with ES6 import syntax when importing a third-party ES5 module that only exports a single unnamed function: module.exports = function (phrase, inject, callback) { ... } Since there is no default export and just an anonymous ...

The table __EFMigrationsHistory does not exist

Trying to navigate the world of .NET Core and facing some challenges. When I enter the following command in the VS Code terminal dotnet ef database update I encounter the following message: Build started... Build succeeded. info: Microsoft.EntityFramework ...

Angular default selection attribute behaving unexpectedly

I am facing an issue with selecting the first option from a dropdown list. Even though I try setting [attr.selected]="index == 1" or [attr.selected]="index == 0", it doesn't work as expected. Surprisingly, when I change the index value condition to [a ...

The parameter of type '{ [key:string]:any;}' cannot be assigned a string argument

When attempting to attach a click event handler on a TypeScript file, I encountered the following error message: Argument of type 'string' is not assignable to parameter of type '{ [key:string]:any;} https://i.sstatic.net/ATkz0.png The ...

Error encountered in Node.js OpenAI wrapper: BadRequestError (400) - The uploaded image must be in PNG format and cannot exceed 4 MB

Attempting to utilize the OpenAI Dall-e 2 to modify one of my images using the official Nodejs SDK. However, encountering an issue: This is the snippet of code: const image = fs.createReadStream(`./dist/lab/${interaction.user.id}.png`) const mask = fs.c ...

Use the jqwidgets jxGrid with the checkbox selection mode to enable row selection by checking for any clicks on the row

Currently, I am using a jqxGrid that contains checkboxes. I would like the ability for users to select a row by clicking on any part or column of the row, not just on the checkbox itself. Unfortunately, it seems this feature is not directly supported. Has ...

Error loading ngs-boostrap in angular2: issues encountered during initialization

Attempting to implement a dropdown menu using ng2-bootstrap component, but encountering an error upon access: Error message received: Failed to load resource: the server responded with a status of 404 (Not Found) Steps taken so far: 1) Installed ng2-boo ...

Could not perform ng build --prod due to inability to negate a statement

When attempting to build my Angular project, which contains bower components in the assets folder, I am using the following command: ./node_modules/.bin/ng build --prod --base-href /project However, upon running the above command, I encounter the follow ...

Deploying an NX micro front-end using docker and Nginx individually for every micro front-end

In my Angular 16 application, I am currently using Nx Micro Front End (MFE) architecture with docker-compose for deployment. All my MFEs are working fine within the same Nginx setup. Now, I want to isolate each MFE into its own container so that they can ...

Pass service API data across initial components within Angular 6

I am currently working on creating a navigation bar that includes categories, as well as a home component that also relies on those same categories. My goal is to avoid making multiple API calls and instead utilize a single variable for the categories thro ...

Excel add-in in Angular featuring exclusive custom functions

I've recently embarked on the journey of developing Office Add-ins, using public code samples to simplify the process. Currently, I am exclusively testing with the web version of Excel. My goal is to merge the functionality of two sample add-ins: one ...

Concern with generic characteristics during type conversion

One of the utilities in my library is a type similar to the following: type Action<Model extends object> = (data: State<Model>) => State<Model>; This utility type allows the declaration of an "action" function that operates against a ...

Deactivate the chosen tab by clicking the Mat-Tab button

I was trying to implement a way to disable the selected mat-tab and its elements when a button is clicked, //HTML <mat-tab-group #tabGroup> <mat-tab *ngFor="let subject of subjects" [label]="subject.name"> {{ subject.name }} ...

Premature updates detected in state cloning process

My program is a simple one designed to showcase an issue I am currently encountering. It involves an array of objects, each containing a sequence number. When a button is clicked, the sequence number of the first object in the array increases by one. To i ...

Ways to access a property within an object using TypeScript

Can you help me extract the "attributes" array from this object and store it in a new variable? obj = { "_id": "5bf7e1be80c05307d06423c2", "agentId": "awais", "attributes": [ // that array. { "created ...