malaika
malaika

Reputation: 461

Uncaught TypeError: Cannot read property '_leaflet_id' of undefined VueJs and Leaflet

I am making a vue project and I want to use leaflet inside of my components. I got the map showing and I can add markers but I run into an error when I try to delete a marker. I get

Uncaught TypeError: Cannot read property '_leaflet_id' of undefined at n (leaflet.js:5) at e.removeLayer (leaflet.js:5) at HTMLInputElement.eval (VM119323 App.vue:74) at HTMLInputElement.dispatch (jquery.js:3058) at HTMLInputElement.eventHandle (jquery.js:2676)

<template>
 <div id="app" class="container-fluid">
  <div class="row">
   <div class="col-md-9">
    <div id="map" class="map" style="height: 781px;"></div>
  </div>
  <div class="col-md-3">

  </div>
</div>
<router-view/>
</div>
</template>

<script>
export default {
 name: "App",
 data() {
return {
  map: null,
  markers: [],
  mapSW: [0, 4096],
  mapNE: [4096, 0],
  tileLayer: null
 };
 },
mounted() {
this.initMap();
this.initLayers();
this.onClick();
this.onPopupOpen();
},
 computed: {
popupContent: function() {
  return "<input type='button' value='Delete' class='marker-delete-button' /> <br> <input type='button' value='Add Event' class='add-event'/>";
 }
},
 methods: {
initMap() {
  this.map = L.map("map").setView([0, 0], 1);
  this.tileLayer = L.tileLayer("/static/map/{z}/{x}/{y}.png", {
    maxZoom: 4,
    minZoom: 3,
    continuousWorld: false,
    noWrap: true,
    crs: L.CRS.Simple
  });
  this.tileLayer.addTo(this.map);

  this.map.on("click", this.onClick, this);

  this.map.setMaxBounds(
    L.LatLngBounds(L.latLng(this.mapSW), L.latLng(this.mapNW))
  );

},
initLayers() {},
onClick(e) {
  var newMarker = L.marker(e.latlng, {
    draggable: true
  })
    .addTo(this.map)
    .bindPopup(this.popupContent);

  this.markers.push(newMarker);


  newMarker.on("popupopen", this.onPopupOpen, this);
},
onPopupOpen(index) {

  $(".marker-delete-button:visible").click(() => {
    this.map.removeLayer(this.newMarker);


  });
  }
}
};
</script>

Upvotes: 1

Views: 11802

Answers (2)

hnrd
hnrd

Reputation: 335

What you can do as well is verifying if the marker is actually on the map before removing it, with the hasLayer method, like so:

if (this.map.hasLayer(this.newMarker)) this.map.removeLayer(this.newMarker);

Upvotes: 0

daniloisr
daniloisr

Reputation: 1367

The scope of newMarker variable should belong to the component in order to you be able to remove it later. Right now it exists only inside onClick method. You can read more about variable scopes here. And in order to solve your problem you need to add newMarker to the data() function:

// ...
data() {
  return {
    // ...
    tileLayer: null,
    newMarker: null
  };
},
// ...
onClick(e) {
  this.newMarker = L
    .marker(e.latlng, { draggable: true })
    .addTo(this.map)
    .bindPopup(this.popupContent);

  this.markers.push(this.newMarker);

  this.newMarker.on("popupopen", this.onPopupOpen, this);
},

onPopupOpen(index) {
  $(".marker-delete-button:visible").click(() => {
    this.map.removeLayer(this.newMarker);
  });
}

You complete code would be something like:

<template>
  <div id="app" class="container-fluid">
    <div class="row">
      <div class="col-md-9">
        <div id="map" class="map" style="height: 781px;"></div>
      </div>
      <div class="col-md-3">

      </div>
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: "App",

  data() {
    return {
      map: null,
      markers: [],
      mapSW: [0, 4096],
      mapNE: [4096, 0],
      tileLayer: null,
      newMarker: null
    };
  },

  mounted() {
    this.initMap();
    this.initLayers();
    this.onClick();
    this.onPopupOpen();
  },

  computed: {
    popupContent: function() {
      return "<input type='button' value='Delete' class='marker-delete-button' /> <br> <input type='button' value='Add Event' class='add-event'/>";
    }
  },

  methods: {
    initMap() {
      this.map = L.map("map").setView([0, 0], 1);
      this.tileLayer = L.tileLayer("/static/map/{z}/{x}/{y}.png", {
        maxZoom: 4,
        minZoom: 3,
        continuousWorld: false,
        noWrap: true,
        crs: L.CRS.Simple
      });
      this.tileLayer.addTo(this.map);

      this.map.on("click", this.onClick, this);

      this.map.setMaxBounds(
        L.LatLngBounds(L.latLng(this.mapSW), L.latLng(this.mapNW))
      );
    },

    initLayers() {},

    onClick(e) {
      this.newMarker = L
        .marker(e.latlng, { draggable: true })
        .addTo(this.map)
        .bindPopup(this.popupContent);

      this.markers.push(this.newMarker);

      this.newMarker.on("popupopen", this.onPopupOpen, this);
    },

    onPopupOpen(index) {
      $(".marker-delete-button:visible").click(() => {
        this.map.removeLayer(this.newMarker);
      });
    }
  }
};
</script>

Upvotes: 3

Related Questions