inocan-group / vue3-google-map

A set of composable components for easy use of Google Maps in your Vue 3 projects.
https://vue3-google-map.com
MIT License
283 stars 57 forks source link

Handling Language and Region Change #18

Closed scottix closed 3 years ago

scottix commented 3 years ago

I am having an issue with the language and region values, when I need to update them to present a different language or region.

Seems like it doesn't like to be loaded again.

Selection_735

I understand the problem is loading the script again, not sure the best way to solve it.

HusamElbashir commented 3 years ago

Hi @scottix,

This coming from js-api-loader. I'm not sure if there's anything we can do about it.

scottix commented 3 years ago

I haven't tested it but thought of maybe deleting the google singleton and deleting the script tag. Looks like this issue has been tossed around here through various issues.

I think I might just force a reload when they change the language for now.

JoseGoncalves commented 3 years ago

I've made a fork to handle the use case were someone needs to dynamic change localization options:

https://github.com/JoseGoncalves/vue3-google-map/tree/dynamic-localization

This fork was made from an early version of vue3-google-map, were there was a different lib (connect-google-maps) used to load the Google Maps API.

But the main idea is that, in order to change the localization options, you need to unload the Google Maps API and load it again.

HusamElbashir commented 3 years ago

@JoseGoncalves Is that similar to js-api-loader's deleteScript? Only problem I see with that solution is if you had multiple maps on the page.

JoseGoncalves commented 3 years ago

@JoseGoncalves Is that similar to js-api-loader's deleteScript?

Don't know that js-api-loader lib. In a nutshell, what I've done in my fork was to add the following function on connect-google-maps:

/**
 * **unload**
 *
 * Unloads the given maps library function (e.g., places, maps, etc.)
 */
export function unload(
  library: IGoogleMapsLibrary
) {
  const script = document.querySelector(`#google-maps-${library}-js`)
  if (script !== null && script.parentNode !== null) {
    script.parentNode.removeChild(script);
    const scriptList = document.querySelectorAll('script[src*="maps.googleapis.com"]');
    scriptList.forEach(el => {
      if (el.parentNode) el.parentNode.removeChild(el);
    });
    delete window.google.maps;
  }
}

and called it when unmounting the GoogleMap component:

diff --git a/src/components/GoogleMap.vue b/src/components/GoogleMap.vue
index fffda9f..0e54f9e 100644
--- a/src/components/GoogleMap.vue
+++ b/src/components/GoogleMap.vue
@@ -6,7 +6,7 @@

 <script lang="ts">
 import { defineComponent, PropType, ref, onBeforeUnmount, watch, toRef } from 'vue';
-import { loadNow } from 'connect-google-maps';
+import { loadNow, unload } from 'connect-google-maps';
 import { useMap } from '../composables/index';
 import {
   IMapOptions,
@@ -144,6 +144,7 @@ export default defineComponent({
     onBeforeUnmount(() => {
       if (map.value) {
         api.value?.event.clearInstanceListeners(map.value);
+        unload('places');
       }
     });

Then, in my app, I've created a new component to wrap the GoogleMap component, were I use a flag to control the map reload with a v-if when the language and/or region is changed:

<template>
    <GoogleMap v-if="mapEnable" api-key="MyKey" :language="language" :region="region" :center="center" :zoom="zoom" />
</template>

<script>
import { ref, watch, nextTick } from 'vue';
import { GoogleMap } from 'vue3-google-map';

export default {
    components: { GoogleMap },

    props: {
        zoom: {
            type: Number,
            required: true
        },
        center: {
            type: Object,
            required: true
        },
        language: {
            type: String,
            default: 'en-GB'
        },
        region: {
            type: String,
            default: 'PT'
        }
    },

    setup(props) {
        const mapEnable = ref(true);
        watch(() => [props.language, props.region], () => {
            mapEnable.value = false;
            nextTick(() => {
                mapEnable.value = true;
            });
        });
        return { mapEnable };
    }
};
</script>
HusamElbashir commented 3 years ago

That's quite clever what you did there 🙂 As for deleteScript I think it's doing a similar thing to what you did with your unload function (minus deleting the singleton of course).

JoseGoncalves commented 3 years ago

It would be nice if something similar would be integrated in the main vue3-google-map...

yankeeinlondon commented 3 years ago

The issue with this solution @JoseGoncalves is that while you're addressing an edge case, you are lowering performance for the average use case. This is not an issue so much as a feature request. I'm happy to consider a PR on this if someone has a solution which doesn't interfere with performance for the happy path.

I am closing this for that reason but as I mentioned, i'm 100% willing to accept a PR from someone if they want to see this in the main codebase.