hexstonedev
hexstonedev

Reputation: 51

Creating map using Leaflet & Vue.js

I am trying to create a map using Leaflet and a Vue component. For some reason the "center: " attribute is not accepting my array coordinates for Latitude and Longitude? When I use it in the template html {{ latlng }} I get an array with the correct coordinates. Any help would be greatly appreciated.

<template>
  <div id="mapContainer">{{ latlng }}</div>
</template>

<script>
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import axios from 'axios';


export default {
  name: "Map",
  data() {
    return {
      map: null,
      latlng: []
    };
  },
  methods: {
    get_lat_lng: function(){
        axios.get('http://127.0.0.1:5000/api/get_latitude')
            .then(res => this.latlng.push(res.data))
        axios.get('http://127.0.0.1:5000/api/get_longitude')
            .then(res => this.latlng.push(res.data))
    }
  },
  created: function(){
      this.get_lat_lng()
  },
  mounted() {

    this.map = L.map("mapContainer", {
        center: this.latlng,
        zoom: 12,
    });
    L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
      attribution:
        '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(this.map);
  },
  beforeDestroy() {
    if (this.map) {
      this.map.remove();
    }
  }
};
</script>

<style scoped>
#mapContainer {
  width: 50vw;
  height: 50vh;
}
</style>

Upvotes: 3

Views: 2753

Answers (2)

Kristof Gilicze
Kristof Gilicze

Reputation: 530

Create the Map when the data is available ( when axios promise is successful ).

More on promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Use a indicator until content not ready.

I think there is no need for separate requests, so i merged the 2 axios requests. Your backend should return the [lat, long] array.

<template>
    <div>
        <!--
         I also added a simple loading indicator,
         obviously you can go for something more fancy like a spinner
        --!>
        <p v-if="loading">Loading...</p>
        <div id="mapContainer">{{ latlng }}</div>
    </div>
</template>

<script>
    import "leaflet/dist/leaflet.css";
    import L from "leaflet";
    import axios from 'axios';

    export default {
        name: "Map",
        data() {
            return {
                map: null,
                loading: false,
                latlng: []
            };
        },
        methods: {
            setupLeafletMap: function () {

                this.map = L.map("mapContainer", {
                    center: this.latlng,
                    zoom: 12,
                });

                L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
                    attribution:
                        '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                }).addTo(this.map);

            }
        },
        mounted() {

            this.loading = true;

            axios.get('http://127.0.0.1:5000/api/get_latlng').then(res => {

                this.latlng = res.data;
                this.setupLeafletMap();  // Creating the Map here ensures that data is already loaded from server side

                this.loading = false;

            }).catch(error => console.error(error));

        },
        beforeDestroy() {
            if (this.map) {
                this.map.remove();
            }
        }
    };
</script>

<style scoped>
    #mapContainer {
        width: 50vw;
        height: 50vh;
    }
</style>

Upvotes: 1

PA.
PA.

Reputation: 29369

You have hit a race condition here. The mounted() hook is called before the axios.get asynchronous call have been completed.

The sequence of calls is probably this 1.created(), 2.mounted(), 3.axios.then()

So, you will need to slightly change your logic so the map is initialized when both the creation has completed and the mount hook has been invoked.

Something like this,

add a flag for the mounted call been executed

data() {
  return {
    map: null,
    mounted: false,
    latlng: null
  }

move the map creation code into a method

createMap: function() {
  this.map = L.map("mapContainer", { center: this.latlng ...

at creation go fetch the data, and if already mounted, create the map

created(){
  axios.all([axios.get('http://127.0.0.1:5000/api/get_longitude');
             axios.get('http://127.0.0.1:5000/api/get_latitude')])
    .then((longresp,latresp)=> {
       this.latlng=[latresp.data,longresp.data];
       if (this.mounted) this.createMap()
     })

and then at mounted, check if by chance the data is already available, and if not, set the flag for the creation of the map

mounted() {
 if (this.latlng) this.createMap()
 this.mounted = true;
 ...

Upvotes: 2

Related Questions