Leaflet – Changing Basemap Sources at Runtime: A Guide for Leaflet Applications

basemaplayer-controlleaflettile-layer

I'm using Leaflet v 1.4.0. In LL, using L.control.layer, the basemap (and overlay) is assigned as follows:

$.fn.initBaseMaps = function (selectedIndexProjectionOption) {
    lyrNASAGIBSBlueMarble = L.tileLayer(nasagibs_static_templates[selectedIndexProjectionOption], nasagibs_static_template_options[selectedIndexProjectionOption]);

    lyrGebcoBathy = L.tileLayer.wms(gebcoWMSServers[selectedIndexProjectionOption], gebco_static_template_options[selectedIndexProjectionOption]);

    baseLayers = [lyrNASAGIBSBlueMarble, lyrGebcoBathy];

    // Define base map object
    objBasemaps = {
        "NASA Blue Marble": lyrNASAGIBSBlueMarble,
        "Gebco Bathymetry": lyrGebcoBathy
    };
    // Define overlays
    objOverlays = {};

    ctlLayers = L.control.layers(objBasemaps, objOverlays, {
        position: 'topright',
        unloadInvisibleTiles: true,
        collapsed: false // temporary
    }).addTo(map);

    //Initial choice
    map.addLayer(baseLayers[0]);
};
$.fn.initBaseMaps(selectedIndexProjectionOption);

This works fine. However, when I change certain 'display conditions', I need to redefine the source of the 2 base layers. How to achieve this?

Note that I am keeping the 2 radio buttons as placeholders and am trying to change the source of the basemaps in runtime. (Please note that I am not asking about how to toggle between radio choices – but change the underlying source of the basemaps).

It seems like even after programmatically removing the baselayers using map.removeLayer(layer), leaflet seems to be storing some internal reference to the old basemaps somewhere and forcing its display as well, along with the newer one. That is, I cannot completely get rid of the older basemaps.

Best Answer

If you would only want to change layer source, that could be done with L.tileLayer.setUrl method. Since you are also changing layer options, the only sensible way is to remove old layer, create new layer and add it to the map. It's impossible to say why this didn't work for you without seeing your code.

Code below should work:

var lyrNASAGIBSBlueMarble = null;
var lyrGebcoBathy = null;
var ctlLayers = L.control.layers({
        position: 'topright',
        unloadInvisibleTiles: true,
        collapsed: false // temporary
    }).addTo(map);

$.fn.initBaseMaps = function (selectedIndexProjectionOption) {
    if (lyrNASAGIBSBlueMarble != null) {
      map.removeLayer(lyrNASAGIBSBlueMarble);
      ctlLayers.removeLayer(lyrNASAGIBSBlueMarble);
      lyrNASAGIBSBlueMarble = null;
    }
    lyrNASAGIBSBlueMarble = L.tileLayer(nasagibs_static_templates[selectedIndexProjectionOption], nasagibs_static_template_options[selectedIndexProjectionOption]);

    if (lyrGebcoBathy != null) {
      map.removeLayer(lyrGebcoBathy);
      ctlLayers.removeLayer(lyrGebcoBathy);
      lyrGebcoBathy = null;
    }
    lyrGebcoBathy = L.tileLayer.wms(gebcoWMSServers[selectedIndexProjectionOption], gebco_static_template_options[selectedIndexProjectionOption]);

    //Initial choice
    map.addLayer(lyrNASAGIBSBlueMarble);

    ctlLayers.addBaseLayer(lyrNASAGIBSBlueMarble, "NASA Blue Marble");
    ctlLayers.addBaseLayer(lyrGebcoBathy, "Gebco Bathymetry");    
};