Exploring the use of leaflets within LitElement

I have been working on a project involving LitElement components and I am looking to incorporate Leaflet into it. However, I am encountering difficulties with displaying the map properly. After installing Leaflet through npm in my project, I created a class that resembles the following code snippet.

import {LitElement, html, css} from 'lit-element';
import './node_modules/leaflet/dist/leaflet';

class Map extends LitElement{

    static get styles() {
        return [css``];
    }

    constructor() {
        super();
    }
    connectedCallback() {
        super.connectedCallback();
        let map = L.map('mapid').setView([51.505, -0.09], 13);

        let urlTemplate = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
        map.addLayer(L.tileLayer(urlTemplate, {minZoom: 4}));
    }

    render() {
        return html`
            <link rel="stylesheet" href="./node_modules/leaflet/dist/leaflet.css">
            <div id="mapid" style="height: 100%"></div>

        `;
    }
}

customElements.define("my-map", Map);

Upon running my application, I encounter the error message: Uncaught TypeError: Cannot set property 'L' of undefined. I am unsure how to effectively utilize Leaflet to showcase a map within my LitElement application and would greatly appreciate any guidance or pointers in the correct direction.

Answer №1

When working on projects involving Lit, we recommend using es-module imports to keep things organized (although this is not mandatory). Instead of simply importing from

import './node_modules/leaflet/dist/leaflet';

try this approach:

import {map as createMap, tileLayer} from './node_modules/leaflet/dist/leaflet-src.esm.js';

Es modules are more compatible with the modular structure of web components and can be optimized effectively by bundlers compared to calling window.L

Update your leaflet calls accordingly. For instance:

let map = L.map('mapid').setView([51.505, -0.09], 13);

// should be
let map = createMap('mapid').setView([51.505, -0.09], 13);

// and
map.addLayer(L.tileLayer(urlTemplate, {minZoom: 4}))

// should be
map.addLayer(tileLayer(urlTemplate, {minZoom: 4}))

Libraries needing a global ID might face issues in web components with shadow DOM as it scopes DOM queries to their roots. Thankfully, leaflet's documentation suggests passing an element reference rather than just an id. To achieve this, fetch the element reference like so:

const mapEl = this.shadowRoot.querySelector('#mapid');

This reference can then be passed into the createMap function

const mapEl = this.shadowRoot.querySelector('#mapid');
let map = createMap(mapEl).setView([51.505, -0.09], 13);

If you encounter the issue where mapEl is null, it may be because LitElement delays rendering its contents until the firstUpdated lifecycle callback. In such cases, move the map creation from connectedCallback to firstUpdated.

An example integrating these changes along with some basic styling for the custom element can be found here: https://jsbin.com/fumusodake/edit?html,output

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

Generate a library using Vue CLI from a component and then import it into your project

When using vue-cli to build my lib, I run the following command: "build": "vue-cli-service build --target lib --name myLib ./src/component.vue" After the build, how can I import my component from the dist folder? Importing from path-to-myLib/src/compone ...

The Next.js website displays a favicon in Chrome, but it does not appear in Brave browser

As I work on my debut next.js website, I am configuring the favicon in index.js like this: <Head> <title>Create Next App</title> <link rel="icon" href="/favicon.ico" /> </Head> Initially, all my source ...

What is the best way to update my component when the selected value is changed?

Currently, I am facing an issue with my map component. It plots polyline data based on the option selected from the select menu component. The problem arises when I change the value in the select menu and click the play button for the animation. Instead of ...

How can I make a clickable button or link within an anchor tag that is still able to be right-clicked?

Hey there, I'm currently working on a notification dropdown menu where each <li> contains a link or an <a> tag. I'm aiming to create something similar to Facebook's notification system. However, the challenge lies in trying to ...

I have a JavaScript code stored as a string that I need to transform into plain JavaScript

If I have a variable in string format, for example suppose there is a JavaScript code inside it: var string="function myFunction(a,b){return a*b;}"; I want to convert this into pure JavaScript code format like so: function myFunction(a, b) { return ...

use javascript or jquery to conceal the textbox control

Looking to conceal a textbox control using javascript or jquery. I attempted the following code: document.getElementsByName('Custom_Field_Custom1').style.display="none"; Unfortunately, I received an error in the java console: document.getEle ...

Any tips for customizing the appearance of a {Switch} component from react-router-dom? I attempted to encase it in a <div> element, but it did

https://i.stack.imgur.com/4piCG.jpg https://i.stack.imgur.com/CyQH3.jpg My code attempts to modify the styling of the map component, but it seems to be influenced by the Switch component. How can I ensure that the screen fits within the 'root' ...

Sending a variable using the onchange function in jQuery

I have written a script to toggle the visibility of different divs based on selection var folder; $(function() { $('#teamleag').change(function() { if ($('#teamleag').val() == 'footballal') { $('# ...

Error: React/Express - The renderToString() function encountered an unexpected token '<'

As I work on implementing server-side rendering for my React/Express application, I have hit a snag due to a syntax error related to the use of the react-dom/server renderToString() method. In my approach, I am following a tutorial mentioned here - The sn ...

In ReactJs, what is the best way to load a new component when a button is clicked?

In ReactJs, I have developed a main component known as MainPage using Material-UI. import React from 'react'; import Grid from '@material-ui/core/Grid'; import Button from '@material-ui/core/Button'; import CssBaseline from & ...

Tips for displaying HTML content using an array in Vue JS

Hi, I'm a beginner with Vue JS and I'm working on passing an HTML table using this array. I have a dropdown where I can select the option I want, but I'm struggling to figure out how to include HTML within it. Whenever I try, it ends up disp ...

Incorporate distinct items into an array using reactjs

I'm facing an issue where clicking on a certain element multiple times adds it to my array multiple times. I need help in figuring out how to add only unique elements to the array. Can anyone offer some guidance? Thank you in advance. const handleCli ...

Having trouble viewing the image slider on an HTML webpage

I've been attempting to incorporate an image slider into my personal website on GitHub, but I've encountered some difficulties as the images are not displaying. Interestingly, I can load individual images without using the slider and they show up ...

Slerping with quaternions in Three.js can produce undesirable outcomes when near the poles

Check out this video example: https://drive.google.com/file/d/18Ep4i1JMs7QvW9m-3U4oyQ4sM0CfIFzP/view In the demonstration, I showcase how I determine the world position of a ray hitting a globe under the mouse cursor. By utilizing lookAt() with a THREE.Gr ...

Error: Appwrite Login Authentication failed due to account.createEmailSession function not recognized as a valid function

Looking for help with Vue and Appwrite? Check out this tutorial: https://appwrite.io/docs/tutorials/vue/step-1 src/appwrite/index.js import { Client, Databases, Account } from "appwrite"; const client = new Client(); client .setEndpoint(" ...

The timing of the RequestAnimationFrame function varies based on the dimensions of my canvas

In my application, I have a canvas that dynamically adjusts its CSS size based on the window size. The main gameplay loop in my code looks like this: run = function(){ console.log(timerDiff(frameTime)); game.inputManage(); game.logics(); ...

What is the best way to merge two JSON arrays using Axios in a React project?

I am currently working on getting data using axios React from Laravel, but I am facing some challenges in combining two arrays by their respective Ids. In my case, I am trying to retrieve product data and images from the Laravel Controller. Can anyone prov ...

Concise way to add or insert an element into an array, at a specific property of an object

I am working with an object of the ObjectOfArrays type: type ObjectOfArrays = { [id: string]: Array<string> }; Throughout my code, I need to add strings to the correct array based on the id. Currently, I am using the following approach: if (id i ...

Display the execution duration on an HTML document

Recently, I created a loan calculator using Javascript and now I'm contemplating on incorporating the time taken for the code to execute into the results. My intention is to have the execution time displayed on my HTML page, but I am unsure of how to ...

Access Images from Server using Front-End Technology

I have a collection of images stored in a server folder that I want to display on a div element using client-side code. Initially, I tried to achieve this with AJAX, but it returned raw data instead of the image URL. Despite my efforts to find a solution, ...