I'm trying to get Google Maps working with Vue.js.
This is the HTML I am using. Assume that v-if="activeStep === 1"
works and is properly displaying the intended div:
<div id="map-container" v-if="activeStep === 1">
<div id='location-map'></div>
</div>
...
<script src="https://maps.googleapis.com/maps/api/js?key=MYKEY"></script>
id styling:
#location-map { height: 250px; }
#map-container { padding: 15px 0; }
and my Vue binding:
if(document.getElementById("map-container")) {
const mapVue = new Vue({
el: '#map-container',
data: {
activeStep: 1,
defaultLatLng: {lat: 37.5665, lng: 126.9780}
},
mounted: function() {
var map = new google.maps.Map(document.getElementById('location-map'), {
zoom: 15,
center: this.defaultLatLng,
scrollwheel: false,
disableDoubleClickZoom: true,
panControl: false,
streetViewControl: false,
draggable: false
});
var marker = new google.maps.Marker({
position: this.defaultLatLng,
map: map
});
}
})
}
But the map is not displaying. Am I doing something incorrectly here?
There are two issues I can think of:
The Google Maps documentation calls the script with a
&callback=initMap
and names the functioninitMap
whereas I haven't done that. Instead, I am having the function call occur with vue's mounted directive. Not sure how I'd call initMap from a vue method. Also, I am not usingasync defer
(like<script async defer src="https://maps.googleapis.com/maps/api/js?key=MYKEY"></script>
) on the script as I read somewhere this was not necessary.The
v-if
actually removes the element and displays it depending on theactiveStep
, so perhaps the map function isn't re-initialized when that part of the DOM is generated?
Any help would be much appreciated. Thanks in advance!
If you are not using async defer with a callback, the order of your Javascript will be important.
And it will also matter if you do use async/defer for other scripts. I suggest using async defer with a callback to ensure that Google maps has loaded properly and so you don't have to worry about order.
If you want to hook up your callback to Vue you can do something like this:
Make your callback point to a global Vue instance:
Create a global Vue instance like so:
Now you can simply have a
createMap
method on your main Vue instance where you can initialize your map.Of course if you are not showing your map container straight away and you display it later on you will have to call a
resize
event on your map to ensure it re-renders.I resolved it by creating a custom directive and binding the initialization script to an
inserted
hook:template:
I think the problem was that v-if creates and destroys the actual HTML so the element was not being re-initialized or something along those lines. This seems to do the trick.
Im pretty sure you havto set a default height in order for it to render.
I know it's an old question but if someone has the same problem ... use v-show instead of v-if.