Vue2-leaflet map not showing properly in BoostrapVue modal Vue2-leaflet map not showing properly in BoostrapVue modal vue.js vue.js

Vue2-leaflet map not showing properly in BoostrapVue modal


There were 3 issues because of which this was happening.

1. First - I forgot to load the leaflet css into main.js - this is why the leaflet map was somehow outside the modal.

//src/main.jsimport '@babel/polyfill';import Vue from 'vue';import './plugins/bootstrap-vue';import App from './App.vue';import router from './router';import store from './store';//above imports not important to this answerimport 'leaflet/dist/leaflet.css'; //<--------------add this linenew Vue({  router,  store,  render: h => h(App),}).$mount('#app');

2. Now the map may disappear. Set a width and height on the l-map component's container. I used a class but you can use style="" etc.

<div class="foobar1"> <!-- <--- Add a class on l-map's container -->  <l-map :center="center" :zoom="13">    <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>    <l-marker :lat-lng="center"></l-marker>  </l-map></div>
<style lang="scss">  .foobar1 { /* <--- class we added above */    width: 100%;    height: 400px;  }</style>

3. Now your map will render within the modal but if you move the map's view, you'll see that leaflet does not download the map's squares in time.You will see something like this:

modal after fixing css but without invalidateSize() fix

To fix this:

  • create an event handler on b-modal for the @shown event.

     <b-modal   @shown="modalShown"   @hidden="$emit('clear')"   size="lg"   :visible="visible"   title="Event details" >

    I called mine modalShown.

  • Then, add a ref attribute to your l-map. I called mine mymap.

    <l-map :center="center" :zoom="13" ref="mymap"> <!-- ref attribute added to l-map -->  <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>  <l-marker :lat-lng="center"></l-marker></l-map>
  • Then, create a modalShown method in the Vue methods for your view/component and call invalidateSize() inside.

    export default {  data() {   //some data here  }  methods: {     modalShown() {      setTimeout(() => {        //mapObject is a property that is part of leaflet        this.$refs.mymap.mapObject.invalidateSize();       }, 100);    }  }}

Now everything should be fine:

  • map should not spill outside the modal
  • map should be visible (duh)
  • map squares should be downloaded when within map body

Here's my full code, it contains some stuff specific to my app but overall it contains all of the code snippets above.


Addtional to Artur Tagisow answer

You can also use this approach to your parent component if your map is in child component.

export default {  data() {   //some data here  }  methods: {     modalShown() {      setTimeout(() => {        window.dispatchEvent(new Event("resize"));      }, 100);    }  }}


For vue.js and nuxt.js developers , probably it's because of using v-show or v-if!in your case display none happening by bootstrap modalbut dont worry the only thing u have to do is using client-only (its like ssr but for new version of js frameworks like nuxt or vue):

<client-only><div id="bootstrapModal"><div id="map-wrap" style="height: 100vh">   <l-map :zoom=13 :center="[55.9464418,8.1277591]">     <l-tile-layer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></l-tile-layer>     <l-marker :lat-lng="[55.9464418,8.1277591]"></l-marker>   </l-map> </div></div></client-only>

ps: if still not loaded in iphone browsers it's probably because of geolocation