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
264 stars 51 forks source link

Uncaught ReferenceError: google is not defined #145

Closed Lars-Sommer closed 1 year ago

Lars-Sommer commented 1 year ago

I have installed vue3-google-map with yarn which now works in my .vue file:

<template>
  <GoogleMap
    id="map"
    ref="mapRef"
    :api-key="Backbone.mapSettings.key"
    :center="Backbone.mapSettings.center"
    :zoom="Backbone.mapSettings.zoom"

    style="width: 100%; height: 100%"
  />
</template>
<script setup lang="ts">
import Backbone from '@/core/Backbone';
import { onMounted } from 'vue';
import { ref, watch } from 'vue';
import { GoogleMap } from 'vue3-google-map';

let gmap: google.maps.Map | null = null;
let mapRef = ref<google.maps.Map | null>(null);

onMounted(() => {
    initMap();
});

function initMap() {
    watch(() => (mapRef.value as any)?.ready as any,    (x) => {
        gmap = (mapRef.value as any).map;
    });
}

</script>>

In another .ts file I try to access the google namespace which is not a problem in the editor linting-wise:

export default class MapSettings {
    public key: string = 'key';
    public zoom: number = 12;
    public center: google.maps.LatLng = new google.maps.LatLng(56.26392, 9.501785);
}

But when the site is compiled in the browser I get this error:

MapSettings.ts:6 Uncaught ReferenceError: google is not defined
    at <instance_members_initializer> (MapSettings.ts:6:38)
    at new MapSettings (MapSettings.ts:3:1)

Adding a reference to the google api in the index.html file removes the problem:

<script src="https://maps.googleapis.com/maps/api/js?key=myKey"></script>

... but I guess this is pretty bad practice, and the console also throws me a warning:

Google Maps already loaded outside @googlemaps/js-api-loader.This may result in undesirable behavior as options and script parameters may not match.

This is my package.json:

"dependencies": {
        "@kyvg/vue3-notification": "^2.9.1",
        "@mdi/font": "7.0.96",
        "@types/google.maps": "^3.53.4",
        "@types/lodash": "^4.14.195",
        "@types/natural-compare-lite": "^1.4.0",
        "axios": "^1.4.0",
        "lodash": "^4.17.21",
        "moment": "^2.29.4",
        "natural-compare-lite": "^1.4.0",
        "vue": "^3.2.0",
        "vue-i18n": "^9.2.2",
        "vue-router": "^4.0.0",
        "vue3-google-map": "^0.15.0",
        "vuetify": "^3.0.0",
        "webfontloader": "^1.0.0"
    },
    "devDependencies": {
        "@babel/types": "^7.21.4",
        "@types/node": "^18.15.0",
        "@types/webfontloader": "^1.6.35",
        "@vitejs/plugin-vue": "^4.0.0",
        "@vue/eslint-config-typescript": "^11.0.0",
        "eslint": "^8.0.0",
        "eslint-plugin-vue": "^9.0.0",
        "typescript": "^5.0.0",
        "prettier": "^2.8.8",
        "vite": "^4.2.0",
        "vite-plugin-vuetify": "^1.0.0",
        "vue-tsc": "^1.2.0"
    }

So how do I make the google namespace accessible from other than .vue files where I directly import 'GoogleMap' ?

HusamElbashir commented 1 year ago

The GoogleMap component can accept a promise that resolves to the global google object if you need to use the google api elsewhere. See the example here https://github.com/inocan-group/vue3-google-map/issues/99#issuecomment-1237395931

Lars-Sommer commented 1 year ago

Thanks alot - it works 👍

But doing so then the duplicate console warning appears: index.ts:8 Google Maps already loaded outside @googlemaps/js-api-loader.This may result in undesirable behavior as options and script parameters may not match.

I guess this is because I first load google maps via the loader, and when the <GoogleMap> component loads it also loads another google maps instance.

Any idea?

HusamElbashir commented 1 year ago

Can you provide a minmial reproduction so I can take a look? You can use vite.new/vue

Lars-Sommer commented 1 year ago

While creating a reproduction repo, I found out what the error was. I was not returning a promise to the <GoogleMap component, but the result of the promise:

const loader = await new Loader({
            apiKey: 'MYKEY',
            libraries: ['drawing', 'geometry', 'places'],
            language: 'da-DK',
            region: 'DA'
        });
        const googleMapsLoader = await loader.load();
        window.google = googleMapsLoader;
        this.vueMapsPromise = googleMapsLoader;

Returning the promise instead, made the warning disappear:

const loader = await new Loader({
            apiKey: 'MYKEY',
            libraries: ['drawing', 'geometry', 'places'],
            language: 'da-DK',
            region: 'DA'
        });
        const googleMapsLoader = loader.load();     
        this.vueMapsPromise = googleMapsLoader;
        window.google = await googleMapsLoader;
        this.center = new google.maps.LatLng(56.26392, 9.501785);

Thanks alot for your help :)

HusamElbashir commented 1 year ago

Glad you got it sorted :)