Search code examples
angulartypescriptleafletproductionleaflet.draw

Leaflet-Draw TypeError: Cannot read properties of undefined (reading 'Event') after Angular 17 production build


I'm encountering an issue with my Angular 17 application where I'm using Leaflet and Leaflet-Draw for map functionality. Everything works perfectly in the development environment, but after building the project for production, I encounter the following error:

ERROR TypeError: Cannot read properties of undefined (reading 'Event')
    at t.initMap (main-LBMRC7E2.js:7:213297)
    at t.ngOnInit (main-LBMRC7E2.js:7:212880)
    at Od (main-LBMRC7E2.js:7:17665)
    at j_ (main-LBMRC7E2.js:7:17812)
    at Hh (main-LBMRC7E2.js:7:17571)
    at oo (main-LBMRC7E2.js:7:17299)
    at fw (main-LBMRC7E2.js:7:40199)
    at ja (main-LBMRC7E2.js:7:41255)
    at hw (main-LBMRC7E2.js:7:39798)
    at Of (main-LBMRC7E2.js:7:39691)

Here’s a snippet of the code where the error occurs:

import {Component, OnInit} from '@angular/core';
import { RouterOutlet } from '@angular/router';
import * as L from 'leaflet';
import 'leaflet-draw'

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <div id="map" style="height: 600px;"></div>
  `,
  styleUrl: './app.component.css'
})
export class AppComponent implements OnInit{
  private map: L.Map | undefined;

  ngOnInit(): void {
    this.initMap();
  }

  private initMap(): void {
    this.map = L.map('map').setView([51.505, -0.09], 13);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
    }).addTo(this.map);

    // Initialize the FeatureGroup to store editable layers
    const drawnItems = new L.FeatureGroup();
    this.map.addLayer(drawnItems);

    // Initialize the draw control and pass it the FeatureGroup of editable layers
    const drawControl = new L.Control.Draw({
      edit: {
        featureGroup: drawnItems
      }
    });
    this.map.addControl(drawControl);

    // Add existing geofence
    const geofence = L.polygon([
      [51.509, -0.08],
      [51.503, -0.06],
      [51.51, -0.047]
    ]);
    drawnItems.addLayer(geofence);


    this.map.on(L.Draw.Event.CREATED, (event: any) => {
      const layer = event.layer;
      drawnItems.addLayer(layer);
    });

    this.map.on(L.Draw.Event.EDITED, (event: any) => {
      const layers = event.layers;
      layers.eachLayer((layer: any) => {
        // Do whatever you want with the edited layers
        console.log('Layer edited:', layer);
      });
    });

    this.map.on(L.Draw.Event.DELETED, (event: any) => {
      const layers = event.layers;
      layers.eachLayer((layer: any) => {
        // Do whatever you want with the deleted layers
        console.log('Layer deleted:', layer);
      });
    });
  }}

The code works fine in development mode without any issues. I’ve checked to make sure that the versions of Leaflet and Leaflet-Draw are compatible with Angular 17.

Additional Information:

  • Angular Version: 17.3.0
  • Leaflet Version: 1.9.4
  • Leaflet-Draw Version: 1.0.4
  • @types/leaflet: 1.9.12
  • @types/leaflet-draw: 1.0.11

Solution

  • After a lengthy debugging session I discovered that the correct import should be:

    import L from 'leaflet';
    

    However I'm still unclear on why the following import does not work:

    import * as L from 'leaflet';
    

    If anyone could explain why the first approach works while the second does not it would be greatly appreciated.