Unable to open popup after marker drag in Leaflet JS

Viewed 75

Using Leaflet JS, I would like to open a marker popup after the user has finished dragging the marker. However, disabling the ability to drag once the "dragend" event is fired prevents the popup to show. The "popupopen" event is fired properly.

The code below does not work on desktop. However, the popup opens just fine after dragging on touch devices.

Removing the ".openPopup();" fixes the problem on desktop browsers, but the issue is then present on touch devices.

var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 19,
  attribution: '© OpenStreetMap'
}).addTo(map);
var marker = L.marker([51.5, -0.09]);
marker.on('dragstart', function() {
  console.log('dragstart');
});
marker.on('drag', function() {
  console.log('drag');
});
marker.on('dragend', function() {
  console.log('dragend');
  this.dragging.disable(); // Uncommenting this line allows the popup to show, but the user is still able to drag the marker.
  this.options.draggable = false;
  var content_string = '<div id="test_div">It works!</div>';
  this.bindPopup(content_string, {
    minWidth: 350,
    closeButton: false
  }).on('popupopen', function(e) {
    console.log('popupopen')
  }).openPopup();
});
map.addLayer(marker);
marker.dragging.enable();
marker.options.draggable = true;

JSFiddle showing how the popup does not open after dragging the marker: https://jsfiddle.net/fnllc/e15mg3b8/19/

1 Answers

The leafletjs docs about the marker were useful, especially noticing that all the normal mouse events were available on a leaflet marker.

It now works as required:

  • Click on marker
  • Drag marker
  • Moves marker around the map
  • Map does not pan
  • Drop marker
  • Popup appears
  • Trying to drag marker does not move the marker but pans the map. Popup does not disappear.

Now you can:

  • Click anywhere on the map to close the popup
  • Click on the marker and drag it ... the popup remains up
  • Drag the map, the popup remains up
  • Once the popup has been closed, the marker can be moved again
  • Clicking on the marker also closes the popup
  • Clicking on the popup does nothing

I instantiated the marker object the same way as before:

var marker = new L.marker([51.505, -0.09], {
  draggable: true,
  autoPan: false,
});

The key point to notice in this code is setting a flag isPoppedUp and testing it at various points in the code. this.dragging.disable() is called in the mousedown event handler.

this.dragging.enable() is called in a new popupclose event handler.

I think there are enough hooks in the code to implement a lot of different functionality now.

I tested it quickly on an android mobile phone and an android tablet, and I think it almost works, but I am not exactly sure what you want to happen on android and iOS devices.

A working version of my code is given here: jsfiddle of stable popup on leaflet map

The full code is listed below, but at the time of writing, it does not run in the code snippet window here.

var isPoppedUp = false;
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 19,
  attribution: '© OpenStreetMap'
}).addTo(map);
var marker = new L.marker([51.505, -0.09], {
  draggable: true,
  autoPan: false,
});
marker.on('mousemouse', function() {
  //    console.log('mousemouse'); 
});
marker.on('mousedown', function() {
  if (isPoppedUp) {
    event.stopPropagation();
    event.preventDefault();
    this.dragging.disable();
  }
  console.log('mousedown', 'isPoppedUp = ', isPoppedUp);
});
marker.on('mouseup', function() {
  if (isPoppedUp) {
    //  isPoppedUp = false;     //  try commenting this in and out
    //  this.dragging.enable(); //  try commenting this in and out
  }
  console.log('mousedown', 'isPoppedUp = ', isPoppedUp);
});
marker.on('dragstart', function() {
  console.log('dragstart', 'isPoppedUp = ', isPoppedUp);
});
marker.on('drag', function() {
  //    console.log('drag'); 
});
marker.on('dragend', function() {
  console.log('dragend', 'isPoppedUp = ', isPoppedUp);
  var content_string = '<div id="test_div">Click anywhere on the map to close the popup<br/>Click on the marker and drag it ... the popup remains up<br/>Drag the map, the popup remains up.<br/>Once the popup has been closed, the marker can be moved again<br/>Clicking on the marker also closes the popup</div>';
  this.bindPopup(content_string, {
    minWidth: 350,
    closeButton: false
  }).on('popupopen', function(e) {
    isPoppedUp = true;
    console.log('popup open', 'isPoppedUp = ', isPoppedUp)
  }).openPopup().on('popupclose', function(e) {
    console.log('popup close', 'isPoppedUp = ', isPoppedUp);
    isPoppedUp = false;     //  try commenting this in and out
    this.dragging.enable(); //  try commenting this in and out
  });;
});
map.addLayer(marker);
<html>

<head>
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin="" />
  <!-- Make sure you put this AFTER Leaflet's CSS -->
  <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script>

  <body>
    <div id="map"></div>
  </body>
</head>

</html> <!-- Please run the JSFiddle code snippet as the one below does not run -->

Related