Transform leaflet marker plugin into Typescript format

I recently discovered a leaflet extension that conceals map markers if they fall outside the boundaries of the current view map.

import L from 'leaflet';

L.Marker.MyMarker= L.Marker.extend({}).addInitHook(function (this: ILazyMarker) {
    this.on(
        'add',
        function (this: ILazyMarker) {
            this._updateIconVisibility = function (this: ILazyMarker) {
                var map = this._map,
                    isVisible = map.getBounds().contains(this.getLatLng()),
                    wasVisible = this._wasVisible,
                    icon = this._icon,
                    iconParent = this._iconParent,
                    shadow = this._shadow,
                    shadowParent = this._shadowParent;

                // keep track of parent of icon
                if (!iconParent) {
                    iconParent = this._iconParent = icon.parentNode;
                }
                if (shadow && !shadowParent) {
                    shadowParent = this._shadowParent = shadow.parentNode;
                }

                // remove or add to DOM based on visibility change
                if (iconParent != null && isVisible != wasVisible) {
                    if (isVisible) {
                        iconParent.appendChild(icon);
                        if (shadowParent != null && shadow) {
                            shadowParent.appendChild(shadow);
                        }
                    } else {
                        iconParent.removeChild(icon);
                        if (shadowParent != null && shadow) {
                            shadowParent.removeChild(shadow);
                        }
                    }

                    this._wasVisible = isVisible;
                }
            };

            // update icon visibility on map size change
            this._map.on('resize moveend zoomend', this._updateIconVisibility, this);
            this._updateIconVisibility();
        },
        this,
    );
});

The functionality works flawlessly, but I prefer using a Typescript class for uniformity across my project. Below is my attempt at converting it:

import L from 'leaflet';

export default class MyMarker extends L.Marker {
    _wasVisible!: boolean;
    _icon!: any;
    _shadowParent!: any;
    _iconParent!: any;

    constructor(latlng: L.LatLngExpression, options?: L.MarkerOptions) {
        super(latlng, options);
    }

    onAdd(): this {
        this._map.on('resize moveend zoomend', this._updateIconVisibility, this);
        this._updateIconVisibility();
        return this;
    }

    _updateIconVisibility() {
        var map = this._map,
            isVisible = map.getBounds().contains(this.getLatLng()),
            wasVisible = this._wasVisible,
            icon = this._icon,
            iconParent = this._iconParent,
            shadow = this._shadow,
            shadowParent = this._shadowParent;

        // remember parent of icon
        if (!iconParent) {
            iconParent = this._iconParent = icon.parentNode;
        }
        if (shadow && !shadowParent) {
            shadowParent = this._shadowParent = shadow.parentNode;
        }

        // add/remove from DOM on change
        if (iconParent != null && isVisible != wasVisible) {
            if (isVisible) {
                iconParent.appendChild(icon);
                if (shadowParent != null && shadow) {
                    shadowParent.appendChild(shadow);
                }
            } else {
                iconParent.removeChild(icon);
                if (shadowParent != null && shadow) {
                    shadowParent.removeChild(shadow);
                }
            }

            this._wasVisible = isVisible;
        }
    }
}

However, when trying to use this marker class, I encounter an error for each marker added and the map fails to render:

TypeError: Cannot read property 'parentNode' of undefined
    at MyMarker._updateIconVisibility (leaflet-my-marker.ts:78)
    at MyMarker.onAdd (leaflet-my-marker.ts:63)
    at MyMarker._layerAdd (leaflet-src.js:6567)
    at NewClass.whenReady (leaflet-src.js:4428)
    at NewClass.addLayer (leaflet-src.js:6629)
    at NewClass.addLayer (leaflet-src.js:6780)
    at VueComponent.addLayer (LLayerGroup.js:164)
    at VueComponent.FirecamMarker.mounted (MyMarker.vue?6277:99)
    at invokeWithErrorHandling (vue.runtime.esm.js:1854)
    at callHook (vue.runtime.esm.js:4219)

Answer №1

According to the "Law of Code Dilemma": No matter how much time you spend troubleshooting a coding issue, the solution will only reveal itself once you seek help on an online forum.

I dedicated several days to dissecting this problem... only to find the answer miraculously shortly after seeking assistance on an online platform. It turns out, I needed to invoke the super's onAdd method within my own onAdd method, as demonstrated below:

onAdd(): this {
    super.onAdd(this._map);
    this._map.on('resize moveend zoomend', this._updateIconVisibility, this);
    this._updateIconVisibility();
    return this;
}

The reason for this oversight was that the original code referenced `addInitHook()` instead of `setInitHook()`, hence the confusion.

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

Angular: issue with form validation - password matching is not functioning as expected

I have successfully implemented the registration form with basic validations The code I used can be found in: registration.html <form #registrationForm="ngForm" (ngSubmit)="onFormSubmit()"> ... <div class="form- ...

Exploring the Power of Vue 3 in Manipulating the DOM

Hello everyone, I am a beginner with Vue and I am interested in learning how to modify the DOM without relying on methods such as document.querySelector or getElementById. Let's take for instance this input: <input id="myInputId" class=& ...

What is the solution to fixing the Vue 2 error when using Node 12?

Issue with Node 12: It seems that there is an error related to the node-sass library in Node 12. Error message from Node: node-pre-gyp ERR! node -v v12.1.0 node-pre-gyp ERR! node-pre-gyp -v v0.10.3 node-pre-gyp ERR! not ok ...

Searching and adding new elements to a sorted array of objects using binary insertion algorithm

I'm currently working on implementing a method to insert an object into a sorted array using binary search to determine the correct index for the new object. You can view the code on codesanbox The array I have is sorted using the following comparis ...

What is the best way to retrieve props for computed properties using Vue with Typescript?

Seeking help on accessing props data for my computed property. Here is the code snippet: <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ props: { color: String, shape: String, ...

Exploring the use of MediaSource for seamless audio playback

Currently working on integrating an audio player into my Angular web application by following a tutorial from Google Developers and seeking guidance from a thread on Can't seek video when playing from MediaSource. The unique aspect of my implementati ...

Challenges with Typescript Integration in Visual Studio 2013

Currently diving into typescript as a newbie while going through the Angular tutorial using Visual Studio 2013 for work, which is also new to me. The frustrating part is that Visual Studio seems to be assuming I am going to use a different language (judgin ...

What is the best way to ensure reactivity in the Vue 2 Provide / Inject API?

After setting up my code in the following manner, I successfully managed to update checkout_info in App.vue using the setter in SomeComponent.vue. However, I noticed that the getter in SomeComponent.vue is not reactive. // App.vue export default { pr ...

Is there a way to monitor user engagement within my app without depending on external analytics platforms?

I'm looking to enhance the user-friendliness of my applications deployed on the Play Store by tracking users' interactions. Specifically, I want to keep track of: Screen Time: Monitoring how much time users spend on each screen. Clicks: Tracking ...

Vue - Sending parameters to computed properties

I am facing an issue with my current code setup: //someFile.Vue <template> <ABC foo="myPath"/> <template> <script> import ABC from 'somewhere'; export default { components: { ABC }, } </script>   / ...

Enhancing Angular 4 classes with dependency injection techniques

Currently utilizing angular 4 and angular cli for my project development. I have created some classes that serve as the base for my components! However, as the constructors of these classes grow during development, I find myself in a phase where I need to ...

Is it possible to execute a block in a v-for loop over an object just once in vue

My current challenge involves handling an object with the following structure: object: { "prop1": [], "prop2": [], "prop3": [], } Within my template, I aim to iterate over this object and display data in each of the props. However, if there is no data ...

Maximizing the potential of mouse positioning in Angular

I am working with an Angular form that has a textarea <textarea class="form-control" id="message" formControlName="message" (fo ...

Guide to slicing strings specifically with numerical characters at the end

I've encountered a challenge. I need to slice the last two characters in a string, but only for strings that contain numbers. I attempted using "nome": element.nome.slice(0,-2) and now I require some sort of validation. However, figuring out how to do ...

Tips for keeping your cool when a listener is suggesting changing it to a const variable

How can I output the isChecked value to the parent component? This value indicates whether the checkbox is clicked or not. Unfortunately, changing it to const is not an option due to an assignment below. My linter is suggesting that I change it to const, ...

How can I extract a specific data value from a JSON file in Ionic 2?

Here is the JSON data: [ { "id": 1, "label": "saw", "total": "100" }, { "id": 2, "label": "saw1", "total": "300" }, { "id": 3, "label": "saw2", "total": "400" } ] Below is my Typescript code snippet: this. ...

In Vue3, have you ever wondered why the $emit function seems to work fine before a promise fetch,

I have encountered an issue while attempting to pass the result of a promise fetch from a child component to a parent component using emit. Strangely, the emit function was working perfectly fine before the $fetch operation, allowing my parent component to ...

The preflight request for Ionic 7 fails the access control check, even though all origins, methods, and headers are permitted

Snippet; this.http.post(this.endpoint + "api/auth/signin", {"username": handle, "password": password}).subscribe(res => { // @ts-ignore if (res["status"] === "authorized") { loc ...

Issue encountered while importing TypeScript files from an external module in a Next.js project

Encountering an issue within my Next.js project with the following project structure: ├── modules/ │ └── auth/ │ ├── index.ts │ ├── page.tsx │ └── package.json └── nextjs-project/ ├─ ...

When using Inertia.js with Typescript, an issue arises where the argument types {} and InertiaFormProps{} are not compatible with the parameter type Partial<VisitOptions> or undefined

I set up a brand new Laravel project and integrated Laravel Breeze along with Typescript support. After creating a form (using useForm()) and utilizing the .post() method with one of the options selected (such as onFinish: () =>), I encountered the fol ...