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

Loïc Monard
  • 680
  • 1
  • 5
  • 13

6 Answers6

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
    })
  })
}
j-printemps
  • 1,288
  • 11
  • 21
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>
Mark
  • 90,562
  • 7
  • 108
  • 148
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.

Vishnu Nair
  • 2,395
  • 14
  • 16
  • 1
    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 – rrrm93 Aug 19 '19 at 14:22
  • I've added scripts but still have error 'google' is not defined no-undef – IHaveHandedInMyResignation May 18 '21 at 11:11
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()
}
...
ege
  • 774
  • 5
  • 19
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

Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109
  • 2
    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. – Yurii N. Oct 06 '18 at 23:01
  • hello, could you check out this question? I am a bit stuck at the map in Vue. https://stackoverflow.com/questions/54479805/using-google-map-in-vue-laravel?noredirect=1#comment95787627_54479805 –  Feb 02 '19 at 07:18
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>
Max Sherbakov
  • 1,817
  • 16
  • 21
  • 4
    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 – Vladd Apr 17 '20 at 07:14