refresh leaflet map: map container is already initialized

JavascriptLeaflet

Javascript Problem Overview


I have a page where given a select to the user he can switch the leaflet map I show.

After a initial leaflet map load, my problem is when i want to refresh the map.

I always get "Map container is already initialized":

The problem line is:

var map = L.map('mapa').setView([lat, lon], 15);

Initially it loads well, but when I select another parameter in the form and want to display the map another time it crashes.

btw, I've tried to destroy and recreate $('#mapa') with jQuery before the second setView() but it shows the same error.

Javascript Solutions


Solution 1 - Javascript

Try map.remove(); before you try to reload the map. This removes the previous map element using Leaflet's library (instead of jquery's).

Solution 2 - Javascript

the best way

map.off();
map.remove();

You should add map.off(), it also works faster, and does not cause problems with the events

Solution 3 - Javascript

Html:

<div id="weathermap"></div>

  

JavaScript:

function buildMap(lat,lon)  {
    document.getElementById('weathermap').innerHTML = "<div id='map' style='width: 100%; height: 100%;'></div>";
    var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                    osmAttribution = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors,' +
                        ' <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
    osmLayer = new L.TileLayer(osmUrl, {maxZoom: 18, attribution: osmAttribution});
    var map = new L.Map('map');
    map.setView(new L.LatLng(lat,lon), 9 );
    map.addLayer(osmLayer);
    var validatorsLayer = new OsmJs.Weather.LeafletLayer({lang: 'en'});
    map.addLayer(validatorsLayer);
}

I use this:

document.getElementById('weathermap').innerHTML = "<div id='map' style='width: 100%; height: 100%;'></div>";

to reload content of div where render map.

Solution 4 - Javascript

Before initializing map check for is the map is already initiated or not

var container = L.DomUtil.get('map');
      if(container != null){
        container._leaflet_id = null;
      }

Solution 5 - Javascript

Only use this

map.invalidateSize();

https://github.com/Leaflet/Leaflet/issues/690

Solution 6 - Javascript

Before initializing map check for is the map is already initiated or not

var container = L.DomUtil.get('map');

if(container != null){

container._leaflet_id = null;

}

map.invalidateSize();

It works for me

Solution 7 - Javascript

well, after much seeking i realized it's well documented at http://leafletjs.com/examples/layers-control.html

i've ended not repainting the map, but print it once and repaint the points on each new ajax call, so the problem was how to clean up the old points and print only the new ones. i've ended doing this:

var point = L.marker([new_marker[0], new_marker[1]]).addTo(map).bindPopup('blah blah');
points.push(point); 
//points is a temporary array where i store the points for removing them afterwards

so, at each new ajax call, before painting the new points, i do the following:

for (i=0;i<points.length;i++) {
  map.removeLayer(points[i]);
}
points=[];

so far, so good :-)

Solution 8 - Javascript

When you just remove a map, it destroys the div id reference, so, after remove() you need to build again the div where the map will be displayed, in order to avoid the "Uncaught Error: Map container not found".

if(map != undefined || map != null){
    map.remove();
   $("#map").html("");
   $("#preMap").empty();
   $( "<div id=\"map\" style=\"height: 500px;\"></div>" ).appendTo("#preMap");
}

Solution 9 - Javascript

What you can try is to remove the map before initialising it or when you leave the page:

if(this.map) {
  this.map.remove();
}

Solution 10 - Javascript

I had the same problem on angular when switching page. I had to add this code before leaving the page to make it works:

    $scope.$on('$locationChangeStart', function( event ) {
    if(map != undefined)
    {
      map.remove();
      map = undefined
      document.getElementById('mapLayer').innerHTML = "";
    }
});

Without document.getElementById('mapLayer').innerHTML = "" the map was not displayed on the next page.

Solution 11 - Javascript

if you want update map view, for example change map center, you don’t have to delete and then recreate the map, you can just update coordinate

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

const setCoordinate = (gps_lat, gps_long) => {
  map.setView([gps_lat, gps_long], 13);
}

initMap();

setCoordinate(50.403723 30.623538);

setTimeout(() => {
  setCoordinate(51.505, -0.09);
}, 3000);

Solution 12 - Javascript

I had same problem.then i set globally map variable e.g var map= null and then for display map i check

if(map==null)then map=new L.Map('idopenstreet').setView();

By this solution your map will be initialize only first time after that map will be fill by L.Map then it will not be null. so no error will be there like map container already initialize.

Solution 13 - Javascript

For refreshing map in same page you can use below code to create a map on the page

if (!map) {
    this.map = new L.map("mapDiv", {
        center: [24.7136, 46.6753],
        zoom: 5,
        renderer: L.canvas(),
        attributionControl: true,
    });
}

then use below line to refresh the map, but make sure to use same latitude, longitude and zoom options

map.setView([24.7136, 46.6753], 5);  

Also, I had the same issue when switching between tabs in the same page using angular 2+, and I was able to fix it by adding below code in Component constructor

var container = L.DomUtil.get('mapDiv');
if (container != null) {
    container.outerHTML = ""; // Clear map generated HTML
    // container._leaflet_id = null; << didn't work for me
}

Solution 14 - Javascript

You should try to unmount the function in react js to remove the existing map.

const Map = () => {

    const mapContainer = useRef();
    const [map, setMap] = useState({});

    useEffect(()=>{
        const map = L.map(mapContainer.current, {attributionControl: false}).setView([51.505, -0.09], 13);

	L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
		maxZoom: 18,
		attribution: 'Map',
		id: 'mapbox/streets-v11',
		tileSize: 512,
		zoomOffset: -1
	}).addTo(map);

    // unmount map function
    return () => map.remove();
    }, []);

    return (
        <div style={{padding: 0, margin: 0, width: "100%", height: "100vh",}}
             ref={el => mapContainer.current = el}>
        </div>
    );
}

Solution 15 - Javascript

use the redrawAll() function rather than renderAll().

Solution 16 - Javascript

We facing this issue today and we solved it. what we do ?

leaflet map load div is below.

<div id="map_container">
   <div id="listing_map" class="right_listing"></div>
</div>

When form input change or submit we follow this step below. after leaflet map container removed in my page and create new again.

$( '#map_container' ).html( ' ' ).append( '<div id="listing_map" class="right_listing"></div>' );

After this code my leaflet map is working fine with form filter to reload again.

Thank you.

Solution 17 - Javascript

If you don't globally store your map object reference, I recommend

if (L.DomUtil.get('map-canvas') !== undefined) { 
   L.DomUtil.get('map-canvas')._leaflet_id = null; 
}

where <div id="map-canvas"></div> is the object the map has been drawn into.

This way you avoid recreating the html element, which would happen, were you to remove() it.

Solution 18 - Javascript

For refresh leaflet map you can use this code:

this.map.fitBounds(this.map.getBounds());

Solution 19 - Javascript

I had the same problem on react I solved it by initialized at the top in useEffect Here is my React Code.

const mapContainerRef = useRef(null);

useEffect( async () => {
  const res =await Axios.get(BASE_PATH + 'fetchProperty')

  const container = L.DomUtil.get(mapContainerRef.current); if(container != null){ container._leaflet_id = null; }

  if(container) {


  const mapView = L.map( mapContainerRef.current, {
    zoom: 13,
    center: [19.059984, 72.889999]
    //  maxZoom: 13
    // minZoom: 15
  });
  // const canvas = mapView.getCanvasContainer();
  mapView.zoomControl.setPosition("bottomright");
  mapView.attributionControl.addAttribution(
    "<a href='https://mascots.pro'>Mascots. pro</a>"
  );
  L.tileLayer(
    // "https://api.mapbox.com/styles/v1/mapbox/dark-v9/tiles/{z}/{x}/{y}?access_token=" + https://api.mapbox.com/styles/v1/anonymousmw/cko1eb1r20mdu18qqtps8i03p/tiles/{z}/{x}/{y}?access_token=
    "https://api.mapbox.com/styles/v1/mapbox/dark-v9/tiles/{z}/{x}/{y}?access_token=" +
      access_token,
    {
      attribution: '<a href="http://mascots.work">Mascots</a>'
    }
  ).addTo(mapView);

  const mask = L.tileLayer.mask(
    "https://api.mapbox.com/styles/v1/anonymousmw/cko1eb1r20mdu18qqtps8i03p/tiles/{z}/{x}/{y}?access_token=" +
      access_token,
    {
      attribution: '<a href="https://mascots.pro">Mascots pro</a>',
      maskSize: 300
      // maxZoom: 18,
      // maxNativeZoom: 16
      // tms: true
    }
  )
  .addTo(mapView);

  mapView.on("mousemove", function (e) {
    mask.setCenter(e.containerPoint);
  });
  res.data.map((marker) => {
  
    const innerHtmlContent = `<div id='popup-container' class='popup-container'> <h3> Property Details</h3>
    <div class='popup-label'>Building Name :<p>${marker.Building}</p></div>
    <div class='popup-address-label'> Address : <p>${marker.Landmark}, ${marker.Location}</p></div>
    <div class='popup-rent-label'>Monthly Rent : <p> ₹ ${marker.Price}</p></div>
    </div>`;
    const divElement = document.createElement("div");
    const assignBtn = document.createElement("div");
    assignBtn.className = "map-link";
    assignBtn.innerHTML = `<button class="view-btn">View Property</button>`;
    divElement.innerHTML = innerHtmlContent;
    divElement.appendChild(assignBtn);
    assignBtn.addEventListener("click", (e) => {
      console.log("dsvsdvb");
    });
    var iconOptions = {
      iconUrl: "/images/location_pin2.svg",
      iconSize: [25, 25]
    };
    var customIcon = L.icon(iconOptions);

    // create popup contents
    var customPopup = divElement;

    // specify popup options
    var customOptions = {
      maxWidth: "500",
      className: "custom"
    };

    const markerOptions = {
      // title: "MyLocation",
      //    draggable: true
      clickable: true,
      icon: customIcon
    };
    const mark = L.marker([marker.Latitude,marker.Longitude], markerOptions);
    mark.bindPopup(customPopup, customOptions);
    mark.addTo(mapView);
    // return mapView.off();
   
  });
  return () => mapView.remove();
}
}, [])

return (
  <div className="map-box">
	    <div className="map-container" ref={mapContainerRef}></div>
	</div>
);

Solution 20 - Javascript

I went through the same problem, so I created a method inside the map instance to reload it.

var map = L.map('mapa').setView([lat, lon], 15);
map.reload = function(){
   map.remove();
   map = L.map('mapa').setView([lat, lon], 15);
}

....

map.reload();

Solution 21 - Javascript

I did this in reactjs

// Create map (dev = reuse existing map)
let myMap = L.DomUtil.get('map');
if(myMap == null){
  myMap = L.map('mapid').setView(currentLocation, zoom);
}

Solution 22 - Javascript

Html:

<div id='leaflet-map' #leafletMap></div>

JavaScript:

@ViewChild('leafletMap')
private mapElement: ElementRef;

private initMap(): void {
   this.map = leaflet.map(this.mapElement.nativeElement, {
       center: [39.01860177826393, 35.30274319309024],
       zoom: 4,
   });

   leaflet
   .tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '',
      maxZoom: 18,
   })
   .addTo(this.map);
}

Solution 23 - Javascript

set

    var container = L.DomUtil.get('map');
    if (container['_leaflet_id'] != null) {
      container.remove();
    }

before var map = L.map('map')

enjoy :)

Solution 24 - Javascript

My hacky implementation to refresh the map was to use:

  // Hack to refresh the map by panning by zero
  public refreshMap() {
    this.map.panBy([0,0]);
  }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionleandro713View Question on Stackoverflow
Solution 1 - JavascriptJoshView Answer on Stackoverflow
Solution 2 - Javascriptyit770View Answer on Stackoverflow
Solution 3 - JavascriptArtem KovalovView Answer on Stackoverflow
Solution 4 - JavascriptDipin Raj CView Answer on Stackoverflow
Solution 5 - JavascriptMahdi BashirpourView Answer on Stackoverflow
Solution 6 - JavascriptwelsonView Answer on Stackoverflow
Solution 7 - Javascriptleandro713View Answer on Stackoverflow
Solution 8 - JavascriptDamicoView Answer on Stackoverflow
Solution 9 - JavascriptSaeed KarimiView Answer on Stackoverflow
Solution 10 - JavascriptDanView Answer on Stackoverflow
Solution 11 - JavascriptРоманView Answer on Stackoverflow
Solution 12 - Javascriptshaishav shuklaView Answer on Stackoverflow
Solution 13 - JavascriptElasticCodeView Answer on Stackoverflow
Solution 14 - JavascriptMuhammad Imran SiddiqueView Answer on Stackoverflow
Solution 15 - JavascriptDilanView Answer on Stackoverflow
Solution 16 - JavascriptMahavar HiteshView Answer on Stackoverflow
Solution 17 - JavascriptJoe EifertView Answer on Stackoverflow
Solution 18 - Javascriptmiko866View Answer on Stackoverflow
Solution 19 - JavascriptJerryView Answer on Stackoverflow
Solution 20 - JavascriptJean Carlo CodognoView Answer on Stackoverflow
Solution 21 - JavascriptPeter FView Answer on Stackoverflow
Solution 22 - JavascriptD.Y. AksuView Answer on Stackoverflow
Solution 23 - JavascriptmahdiView Answer on Stackoverflow
Solution 24 - JavascriptRosscoView Answer on Stackoverflow