29

I've been trying to initialize a Google map on my vue.js project while including the script :

<script src="https://maps.googleapis.com/maps/api/js?key="MY_API_KEY"&callback=initMap" async defer></script>

The problem is that my .vue files look like that :

<template>
  ...
</template>

<script>
  ...
</script>

And I can't include more than one script tag in my vue file, I can show the map while passing by the index.html but I dont really want to put js on the index.html, + I can't point the script callback on a vue method.

Do you guys have some ideas on how to show up that map using a .vue file ? I did use vue2-google-maps but I'd like to use the original google map.

I have a fiddle which is doing something ok : https://jsfiddle.net/okubdoqa/ without using a callback in the script tag, but it doesnt work for me ... Thanks

1

6 Answers 6

22

I'd suggest using npm google-maps instead of adding a script in index.html. You might not need to call google-maps API in every pages, and I'd say it's better to use Webpack properly. You can use npm install google-maps

import GoogleMapsLoader from 'google-maps'

mounted: function () {
  GoogleMapsLoader.load(function(google) {
    let map = new google.maps.Map(document.getElementById('map'), {
      zoom: 15,
      center: position
    })
  })
}
Sign up to request clarification or add additional context in comments.

3 Comments

does this package provide the same service? github.com/googlemaps/google-maps-services-js tnks
Google-maps-services-js is for NodeJs, not the client-side.
this always return calling load on undefined
21

It's a little fussy to get this working without using a library, and there are probably cleaner ways, but you can simply import the library and use it in your components if you want to get up and running.

First, don't use the defer & async options in the <script> tag. Load it in the index.html:

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

Then in your component you can access the global google and pass it an element once the component is setup. For example using the setup from the Vuejs cli:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>

    <div id="myMap"></div>
  </div>
</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }},
  mounted: function() {
        console.log("map: ", google.maps)
            this.map = new google.maps.Map(document.getElementById('myMap'), {
            center: {lat:61.180059, lng: -149.822075},
            scrollwheel: false,
            zoom: 4
            })
  }

}
</script>
<style scoped>
    #myMap {
    height:300px;
    width: 100%;
   }
</style>

5 Comments

Thank you for your replay, unfortunately I have an error saying "Error in mounted hook: "ReferenceError: google is not defined" like if the script wasnt even there...
Ok nevermind I just put the script in the head tag of the index instead of the body and it worked
This reference error is coming from ESLint. Add google as a global variable stackoverflow.com/a/30400159
You can use async & defer, see C2486 answer and my comment above.
How to add snazzy map styling data for google maps!
18

I was searching for a different issue and found this one, there is another way that you could achieve this without having to add it in index.html.

I faced a similar problem where I had to use two Google API keys for different environments so hard-coding it in to index.html was not a good idea, I did this if it helps anyone -

main.js

export const loadedGoogleMapsAPI = new Promise( (resolve,reject) => {

      window['GoogleMapsInit'] = resolve;

      let GMap = document.createElement('script');

      GMap.setAttribute('src',
     `https://maps.googleapis.com/maps/api/js?key=${process.env.GOOGLE_API_KEY}&callback=GoogleMapsInit&region=IN`);

      document.body.appendChild(GMap); 
});

MapElem.vue

<template>
   <div id="map"></div>
</template>

<script>
   import {loadedGoogleMapsAPI} from '@/main'

   export default {
     name: 'MapEl',
     mounted(){  
       loadedGoogleMapsAPI.then(()=>{
         this.initMap()
       });
     },
    methods:{
     initMap(){
        console.log(google.maps); //You can now access google maps object here
        new google.maps.Map(document.getElementById('map'), {
          // You configuration goes here
        })
     }
    }
</script>

It's pretty straightforward, you write a Promise in main.js which will resolve to the callback initiated by Google script ( which we dynamically appended to the body ). Once the Promise is resolved you can access the map object in your component.

2 Comments

the best example I've seen so far, for some reason the maps weren't working in productions only on localhost i used vue2-google-maps and nuxt-google-maps-module, after adding your code it works fine on production i just had to wrap the function inside if (process.client) with nuxt
I've added scripts but still have error 'google' is not defined no-undef
3

There's a different way if you would like to keep the code contained in a Component using the async loader $Scriptjs.

Install via npm

npm install scriptjs

import into your component

import $Scriptjs from 'scriptjs

load the script in the mounted hook (assuming you have a method in your component called initMap)

...
mounted () {
  $Scriptjs('https://maps.googleapis.com/maps/api/js?key={YOUR_KEY}', () => {
      this.initMap()
}
...

Comments

3

Initial vue part after Using google map callback function.

function initMap(){	
	var app = new Vue({
		el:"#app",
		data:{
			name:"Niklesh Raut",
			map:"",
			mapOptions:{}
		},
		mounted(){
			this.initMap();
		},
		methods:{
			initMap: function(){
				this.mapOptions = {
					center: new google.maps.LatLng(21.139808079490507, 79.07690763473511),
					zoom: 10,
					mapTypeId: 'roadmap'
				}
				this.map = new google.maps.Map(document.getElementById("map"), this.mapOptions);
			}
		}
	});
}
.wrapper {
    display: flex;
    width: 100%;
    align-items: stretch;
}
#content {
    width: 100%;
    /*padding: 20px;*/
    min-height: 100vh;
    transition: all 0.3s;
}
.map{
    height: 100%;
    width:100%;
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDUFmbwJMBHU_paeMfVO7oqPC1IJEtbJUU&callback=initMap"></script>	
</head>	

<div id="app" class="wrapper">
	<div id="content">
		Name : {{name}}
		<div id="map" class="map"></div>
	</div>
</div>

Jsfiddle Link

2 Comments

Better answer than the accepted, however your application is fully dependent on google map's callback, which isn't the best deal. I'd rather suggest to use window.addEventListener("load", onPageLoad, false);, where onPageLoad function loads new Vue instance correspondingly.
hello, could you check out this question? I am a bit stuck at the map in Vue. stackoverflow.com/questions/54479805/…
1

Best and simple way to integrate Google Maps to Vue is use npm's libs. You need to use vue-google-maps

npm install vue2-google-maps

then,

import Vue from 'vue'
import * as VueGoogleMaps from 'vue2-google-maps'

Vue.use(VueGoogleMaps, {
  load: {
    key: 'YOUR_API_TOKEN',

  },


})

Just simple paste code below:

<GmapMap
  :center="{lat:10, lng:10}"
  :zoom="7"
  map-type-id="terrain"
  style="width: 500px; height: 300px"
>


</GmapMap>

1 Comment

neither best or simple. Completely relying to some third party code, that you cant make work as you want is not the best direction. Implementing map is the best when you work directly with google api and do whatever you want

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.