Home > Back-end >  Vue3 Google Maps marker cannot be removed
Vue3 Google Maps marker cannot be removed

Time:11-17

I have got a mostly functioning self made system for handling google maps in Vue3. I haven't used libraries because none have quite the functionality that I want (eventually), and it seemed relatively straightforward to implement myself (which it has been up until this issue).

The Map component is as follows:

<template>
    <div class="map-container">
        <div class="google-map" ref="map"></div>
        <div>
            <slot></slot>
        </div>
    </div>
</template>

<script>
import { Loader } from '@googlemaps/js-api-loader';

export default {
    props: { 
        latitude: {
            type: [String, Number],
            default: 0
        }, 
        longitude: {
            type: [String, Number],
            default: 0
        },
        zoom: {
            type: Number,
            default: 15
        },
    },
    data(){
        return {
            map: null,
            api: null,
            move: null,
        }
    },
    provide: function () {
        return {
            getMap: this.getMap
        }
    },
    watch: {
        latitude(){ this.updateCenter() },
        longitude(){ this.updateCenter() }
    },
    methods: {
        getMap(callback){
            var self = this;
            function checkForMap() {
              if (self.map) {
                callback(self.map, self.api);
              } else {
                setTimeout(checkForMap, 50);
              }
            }
            checkForMap();
        },
        updateCenter(){
            let center = new this.api.LatLng(this.latitude, this.longitude);
            this.map.panTo(center);
        }
    },  
    mounted(){
        let self = this
        let apiKey = document.getElementById('GOOGLE_MAPS_KEY').value
        let loader = new Loader({
            apiKey:  apiKey,
            version: "weekly",
            libraries: ["geometry"]
        });
        loader.load()
            .then((google) => {
                self.api = google.maps;
                self.map = new google.maps.Map(self.$refs.map, {
                    center: {
                        lat: parseFloat(self.latitude), 
                        lng: parseFloat(self.longitude)
                    },
                    zoom: self.zoom,
                    disableDefaultUI: true,
                });

                // Configure the click listener.
                self.map.addListener("click", (mapsMouseEvent) => {
                    self.$emit('click', mapsMouseEvent)
                });

                // Configure the move listener.
                self.map.addListener("bounds_changed", () => {   
                    if(self.move) clearTimeout(self.move);
                    self.move = setTimeout(() => {
                        let bounds = self.map.getBounds(true);
                        let center = self.map.getCenter();
                        let radius = 100000;

                        if(bounds && center){
                            let northEast = bounds.getNorthEast();
                            radius = self.api.geometry.spherical.computeDistanceBetween(center, northEast);
                        }

                        self.$emit('move', {
                            bounds: bounds,
                            radius: Math.round(radius),
                            center: {
                                latitude: center.lat(),
                                longitude: center.lng()
                            }
                        })
                    }, 800); 
                });
              
            })
            .catch(e => {});
  
    }    
}
</script>

And the marker component is as follows:

<template>
    <div></div>
</template>

<script>
export default {
    props: {
        latitude: String, 
        longitude: String, 
        icon: {
            type: String,
            default: '/images/pin.png'
        }
    },
    data(){
        return {
            map: null,
            api: null,
            marker: null
        }
    },
    inject: ["getMap"],
    watch: {
        latitude(){ this.updatePosition() },
        longitude(){ this.updatePosition() }
    },
    mounted(){
        let self = this
        this.getMap(function(map, api){
            self.map = map;
            self.api = api;

            self.marker = new api.Marker({
                position: new api.LatLng(self.latitude, self.longitude),
                map: map,
                icon: self.icon,
            });

            self.marker.addListener("click", () => {
                self.$emit('click', self.marker)
            });
        })
        
    },
    beforeUnmount(){
        this.marker.setMap(null);
        this.marker = null;
    },
    methods: {
        updatePosition(){
            this.marker.setPosition( new this.api.LatLng( parseFloat(this.latitude), parseFloat(this.longitude) ) );
        }
    }
}
</script>

I then have a component that is using these components to display a map with markers on it.

<template>    
    <div>
        <div class="admin-site-map">
            <google-map :center="center" :zoom="15">
                <map-marker v-for="site in sites" :key="site.id" 
                    :latitude="site.latitude" 
                    :longitude="site.longitude" 
                    @click="markerClicked"
                />
            </google-map>        
        </div>
    </div>
</template>

<script>
import GoogleMap from '@/components/Core/Maps/GoogleMap';
import Marker from '@/components/Core/Maps/Marker';
export default {
    components: { GoogleMap, mapMarker: Marker },  
    props: ['sites'],
    data(){
        return {
            center: {lat: 0, lng: 0},
        }
    },
    methods: {
        markerClicked(value){
            console.log('click: ', value)
        }  
    }
}
</script>

When the list of markers (sites) change, I can see the beforeUnmount method called on the markers that have been removed, but the marker doesn't disappear from the map, I can still even click on the marker and receive a null value emitted in the event. Oddly, calling this.marker.setVisible(false) does work, and hides the marker. I've been stuck on this for a while, so any insight or help would be appreciated. Thanks!

CodePudding user response:

Thanks to User28, I eventually found the solution: On the marker component, marker (which is where the Google marker object is saved to) should not be a reactive property. Changing the data method to

return {
    map: null,
    api: null
}

fixed the issue (i.e. remove marker).

  • Related