skip to Main Content

I want to add a button to an L.control() infobox in a leaflet map. Nevermind what the original intent of the button was, now I just want to know why this does not work (info.buttonClicked() is not called when the button is clicked):

let map;

map = L.map("map").setView([45.0, 0.0], 8);

var tiles = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  maxZoom: 19,
}).addTo(map);

let info = L.control();

info.onAdd = function (map) {
  this._div = L.DomUtil.create("div", "info");

  var button = L.DomUtil.create('button', 'close-btn', this._div);
  button.innerHTML = 'x';
  button.style.float = 'right';

  button.addEventListener('click', function() {
    console.log('buttonClicked event');
    info.buttonClicked();
  });

  this._div.innerHTML += "some info";

  return this._div;
};

info.buttonClicked = function() { 
  console.log('info.buttonClicked() called');
  //this._div.innerHTML += ''; 
};

info.addTo(map);


(full example here), whereas this works (rest of the code is the same):

info.onAdd = function (map) {
    this._div = L.DomUtil.create("div", "info");

    this._div.innerHTML = '<button style="button" onclick="info.buttonClicked()" id="minimize-btn">x</button>';
    this._div.innerHTML += "some info";

    return this._div;
};

In the first case I don’t see any error messages but nothing happens. Why?

NOTE: adding L.DomEvent.disableClickPropagation(this._div);, as suggested in one of the answers below, doesn’t fix this.

2

Answers


  1. Chosen as BEST ANSWER

    The culprit is the line:

    this._div.innerHTML += "some info";
    

    It destroys (and then recreates) all child elements of this._div so the event listener associated with the original button is lost.

    If you replace this line with say:

    let contentDiv = L.DomUtil.create("div", "info-content", this._div);
    contentDiv.innerHTML = "some info";
    

    the button will work as intended.


  2. The issue arises because Leaflet’s L.DomEvent system intercepts events on the map and might prevent events from propagating to elements added to the map’s controls or layers. Specifically, when using L.DomUtil.create() to create elements and appending them to the map’s DOM, Leaflet might block or modify the default event behavior, such as click.

    To resolve this issue, you need to ensure the event properly propagates and is not being stopped by Leaflet’s event-handling system.

    Here’s how to fix your code:

     let map;
    
    map = L.map("map").setView([45.0, 0.0], 8);
    
    var tiles = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
      maxZoom: 19,
    }).addTo(map);
    
    let info = L.control();
    
    info.onAdd = function (map) {
      this._div = L.DomUtil.create("div", "info");
    
      // Create the close button
      var button = L.DomUtil.create("button", "close-btn", this._div);
      button.innerHTML = "x";
      button.style.float = "right";
    
      // Ensure Leaflet doesn't block the button's click events
      L.DomEvent.disableClickPropagation(this._div);
    
      // Attach the click event
      button.addEventListener("click", () => {
        console.log("buttonClicked event");
        info.buttonClicked();
      });
    
      // Add some informational content
      this._div.innerHTML += "some info";
    
      return this._div;
    };
    
    info.buttonClicked = function () {
      console.log("info.buttonClicked() called");
      // Remove the control from the map
      map.removeControl(info);
    };
    
    // Add the control to the map
    info.addTo(map);
    

    Key Fixes and Explanations:

    Disable Click Propagation:

    The line L.DomEvent.disableClickPropagation(this._div); ensures that clicks on the info control (including the button) don’t propagate to the map. Without this, Leaflet might treat clicks as map interactions, interfering with your button’s event handling.

    Event Listener:

    Use a standard button.addEventListener("click", …) to bind the click event to the button. This works fine as long as disableClickPropagation is in place.

    Remove Control:

    The info.buttonClicked() method demonstrates how you can use the removeControl() method to remove the control when the button is clicked.

    Testing:
    Place this code in your project and verify that the button is functional.
    Open the browser console and confirm that clicking the button logs the appropriate messages and removes the control from the map.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search