Leaflet – How to Attach Click Function to Button Inside a Popup Using JQuery

buttonjqueryleafletpopup

I'm trying to create a button inside a popup which will draw a line on the map when clicked. Line coordinates must be based on the properties of the point layer.

I saw some ansewrs on stack and it should look like this http://jsfiddle.net/cfsg6t7u/ but the coords are hardocded and it should be based on the point layer data.

In my code buttons make no action. Here is my HTML file with js:

<!DOCTYPE html>
    <html>
        <head>
            <title>test</title>
            <meta charset="UTF-8">
    
            <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"/>
            <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    
            <script type="text/javascript" src="./points.js"></script>
    
            <style>
                html, body {
                    height: 100%;
                    margin: 0;
                }
                #map {
                    width: 100%;
                    height: 100%;
                }
            </style>
        </head>
    
        <body>
            <div id='map'></div>
    
            <script>
                var map = L.map('map').setView([0, 0], 5)
                var OSM = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
    
                var pointsLayer = L.geoJSON(points, {
                    pointToLayer: function (feature, latlng) {
                        var content = feature.properties.name;
                        content += "<br><button id='draw" + feature.properties.name + "'>draw a line</btn>";
                        
                        $("#draw" + feature.properties.name).click(function() {
                        var line = L.polyline([[latlng.lat, 0], [latlng.lng, 360]])
                        });
    
                        return L.marker(latlng).bindPopup(content);
                }})
                
                pointsLayer.addTo(map);
            </script>
        </body>
    </html>

Here is another version of adding clickable button but it gives an html object:

var pointsLayer = L.geoJSON(points, {
            pointToLayer: function (feature, latlng) {

                return L.marker(latlng).bindPopup(feature.properties.name + '<br>' +
                 $("<button id='draw" + feature.properties.name + "'>draw a line</button>").click(function() {
                var line = L.polyline([[latlng.lat, 0], [latlng.lng, 360]]);
                })[0]);
        }})

Here is sample points.js data:

    var points = {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
                                                                                                                                  
"features": [
{ "type": "Feature", "properties": { "name": "pierwszy"}, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } },
{ "type": "Feature", "properties": { "name": "drugi"}, "geometry": { "type": "Point", "coordinates": [ 0, 5 ] } },
]}

I know Leaflet and JS as little as it works enough to aim my goal.

EDIT:

Because this question got a lot of views here is my final map with buttons I wanted to create. Maybe it will be helpful to see the result for people who want to achieve similar effect.
https://marylagis.github.io/webmaps/citiesonlines/

Best Answer

No need to use jQuery here IMHO. You can pass an HTMLElement to the bindPopup function. So just create a div and the button as javascript objects and construct the container that way. Then you can add an onclick function to the button where you can access the latlng or the whole feature.

Working JsFiddle.

const points = {
  "type": "FeatureCollection",
  "crs": {
    "type": "name",
    "properties": {
      "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
    }
  },

  "features": [{
      "type": "Feature",
      "properties": {
        "name": "pierwszy"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [0, 0]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "name": "drugi"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [0, 5]
      }
    },
  ]
}
const map = L.map('map').setView([0, 0], 5);
const osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);

const pointsLayer = L.geoJSON(points, {
  pointToLayer: (feature, latlng) => {
    const div = document.createElement("div");
    div.innerHTML = `<br>${feature.properties.name}<br>`;

    const button = document.createElement("button");
    button.innerHTML = "Create Line";

    button.onclick = function() {
      const line = L.polyline([latlng, [10, 5]]);
      line.addTo(map);
    }

    div.appendChild(button);

    return L.marker(latlng).bindPopup(div);
  }
});

pointsLayer.addTo(map);