Skip to content

How to generate markers from an api in leaflet?

I’m making in app using vue and leaflet and I need to generate markers from and API. But for some reason, only the default markers are showing. I can access the api data in the DOM. I just can’t figure out how to iterate over it and show the data on the DOM. pls help

here’s the code

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.12/vue.js"></script>
<template>
  <div class="containerTest">
    <div style="height: 80vh">
    <LMap :zoom="zoom" :center="center">
      <LTileLayer :url="url"></LTileLayer>
      <l-marker
        :key="index"
        v-for="(brew, index) in markers"
          :lat-lng="latLng(brew.latitude, brew.longitude)"
      ></l-marker>
      <!-- <LMarker :lat-lng="[47.413220, -1.219482]"></LMarker>
      <LMarker :lat-lng="[46.193220, 4.82]"></LMarker>
      <LMarker :lat-lng="[45.193220, 6.82]"></LMarker>
      <LMarker :lat-lng="[47.03220, -0.9482]"></LMarker>
      <LMarker :lat-lng="[46.03220, 2.9482]"></LMarker> -->
    </LMap>
  </div>
  </div>

</template>
      
<script>

import { LMap, LTileLayer, LMarker } from "vue2-leaflet";

export default {
  name: "Map",
  components: {
    LMap,
    LTileLayer,
    LMarker
  },
  data() {
    return {
      markers: [],
      url: "https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=CFmlXsYmVozAdWKEtdT5",
      zoom: 6,
      center: [46.5322, 2.9482],
      bounds: null
    };
  },
  mounted: function () {
    fetch('https://api.openbrewerydb.org/breweries').then((response) => {
      return response.json();
    }).then(json=>{
        this.brews = json
        console.log(this.brews)
    })
  },
  methods: {
    latLng: function(lat, lng) {
      return L.latLng(lat,lng);
    },
  }
};
</script>

Answer

You are storing data from API in a variable this.brews which does not exists in data. Then you are rendering markers from markers array which is empty and not modified at all…

To fix it:

  1. store the data (this.breweries in example below)
  2. Add computed property markers which generates the data you need for rendering…

const vm = new Vue({
  name: "Map",
  el: '#app',
  components: {
    'l-map': window.Vue2Leaflet.LMap,
    'l-tile-layer': window.Vue2Leaflet.LTileLayer,
    'l-marker': window.Vue2Leaflet.LMarker,
  },
  data() {
    return {
      url: "https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=CFmlXsYmVozAdWKEtdT5",
      zoom: 11,
      center: [32.714813, -117.129593],
      bounds: null,
      breweries: []
    };
  },
  mounted: function() {
    fetch('https://api.openbrewerydb.org/breweries?by_city=san_diego')
      .then((response) => {
        return response.json();
      }).then(data => {
        this.breweries = data
        //console.log(this.breweries)
      })
  },
  computed: {
    markers() {
      return this.breweries
        .filter((br) => br.latitude && br.longitude) // only breweries with lat + lon data
        .map((br) => ({
          ...br,
          markerLatLng: [br.latitude, br.longitude]
        }))
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.12/vue.js"></script>
<link rel="stylesheet" href="//unpkg.com/leaflet/dist/leaflet.css" />
<script src="//unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="//unpkg.com/vue2-leaflet"></script>

<div id="app">
  <div class="containerTest">
    <div style="height: 80vh">
      <l-map :zoom="zoom" :center="center">
        <l-tile-layer :url="url"></l-tile-layer>
        <l-marker :key="brew.id" v-for="(brew, index) in markers" :lat-lng="brew.markerLatLng"></l-marker>
      </l-map>
    </div>
  </div>
</div>