Skip to content

Add a delete button for markers in popups when using a local HTML file in Folium #2099

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dhyanKaro opened this issue Feb 28, 2025 · 4 comments

Comments

@dhyanKaro
Copy link

dhyanKaro commented Feb 28, 2025

I’m working with Folium and generating a map saved as a local HTML file using save(). I’d like to add functionality where each marker in the popup has a delete button (such as a trash icon) that allows the user to remove the marker from the map permanently. Something like this for the trash icon:

html = f"""<div><a href="#" class="delete-marker" data-marker-id="{marker_id}" title="Remove this marker">
                <i class="fa fa-trash"></i>
              </a></div>"""
marker = folium.Marker(location=[lat, lon], popup=html, ...)

However, I’m not sure how to implement the functionality to actually remove the marker from the map after the button is clicked, especially when working with a static, locally saved HTML file. Is there a way to achieve this with Folium, or would I need to implement custom JavaScript for this behavior?

@hansthen
Copy link
Collaborator

hansthen commented Mar 1, 2025

You'll need to write some javascript to do this. This can be done inline, in the html you pass as argument to the popup. The trickiest part is to get the javascript reference for the Marker you want to remove and the javascript reference for the map. Also, you probably need to add the popup after you have instantiated the Marker. The following is completely untested, but it should look something like this:

map_ref = map.get_name()
marker = folium.Marker(location=[lat, lon])
marker_ref = marker.get_name()

html = f"""<div><a href="#" class="delete-marker" data-marker-id="{marker_id}" title="Remove this marker"
onclick="{map_ref}.removeLayer({marker_ref});">
                <i class="fa fa-trash"></i>
              </a></div>"""
popup = Popup(html)
marker.add_child(popup)

Let me know what your progress is.

@dhyanKaro
Copy link
Author

It works, thanks. Any way to make the deletions persist across refreshes?

import folium

# Create a map
m = folium.Map(location=[37.7749, -122.4194], zoom_start=12)

# Create some markers with delete buttons
for i, location in enumerate([
    [37.7749, -122.4194],  # San Francisco
    [37.8044, -122.2712],  # Oakland
    [37.3382, -121.8863]   # San Jose
]):
    # Create marker
    marker = folium.Marker(location=location, tooltip=f"Point {i+1}")
    
    # Get references for JavaScript
    map_ref = m.get_name()
    marker_ref = marker.get_name()
    
    # Create HTML with delete button
    html = f"""
    <div>
        <h4>Marker {i+1}</h4>
        <p>This is a sample marker.</p>
        <button onclick="{map_ref}.removeLayer({marker_ref}); return false;" 
                style="background-color: #ff4444; color: white; border: none; 
                       padding: 5px 10px; border-radius: 3px; cursor: pointer;">
            Delete Marker
        </button>
    </div>
    """
    
    # Add popup with delete button
    popup = folium.Popup(html)
    marker.add_child(popup)
    
    # Add marker to map
    marker.add_to(m)

# Save the map
m.save('deletable_markers.html')

@hansthen
Copy link
Collaborator

hansthen commented Mar 7, 2025

That's a lot trickier. You'd need some kind of storage (like a database) to determine what markers to display. In the click handler you'd also need to update the storage. Probably bare folium is not the best solution for this.

You could take a look at streamlit-folium. This package allows you to display a folium map inside a streamlit application. Inside your streamlit application you could initialize and update your storage.

@dhyanKaro
Copy link
Author

Thanks, yeah, I kind of got this to work, using localstorage, but it seems to do it all via JavaScript. A bit beyond me.

import folium
import json

# Create a map
m = folium.Map(location=[37.7749, -122.4194], zoom_start=12)

# Define markers
markers_data = [
    {"id": "marker1", "location": [37.7749, -122.4194], "title": "San Francisco"},
    {"id": "marker2", "location": [37.8044, -122.2712], "title": "Oakland"},
    {"id": "marker3", "location": [37.3382, -121.8863], "title": "San Jose"}
]

# Add JavaScript to handle persistence and immediate deletion
js_code = """
<script>
// Store marker references
var markerObjects = {};

// Function to initialize markers
function initMarkers() {
    // Get deleted markers from localStorage
    let deletedMarkers = JSON.parse(localStorage.getItem('deletedMarkers') || '[]');
    
    // Create markers that weren't deleted
    let markersData = %s;
    for (let i = 0; i < markersData.length; i++) {
        if (!deletedMarkers.includes(markersData[i].id)) {
            createMarker(markersData[i]);
        }
    }
}

// Function to create a marker
function createMarker(markerData) {
    let marker = L.marker(markerData.location).addTo(%s);
    markerObjects[markerData.id] = marker;
    
    let html = `
        <div>
            <h4>${markerData.title}</h4>
            <button onclick="deleteMarkerPermanently('${markerData.id}'); return false;" 
                    style="background-color: #ff4444; color: white; border: none; 
                           padding: 5px 10px; border-radius: 3px; cursor: pointer;">
                Delete Permanently
            </button>
        </div>
    `;
    marker.bindPopup(html);
    return marker;
}

// Function to delete marker and save state
function deleteMarkerPermanently(markerId) {
    // Get deleted markers from localStorage
    let deletedMarkers = JSON.parse(localStorage.getItem('deletedMarkers') || '[]');
    
    // Add this marker ID to deleted list
    if (!deletedMarkers.includes(markerId)) {
        deletedMarkers.push(markerId);
    }
    
    // Save updated list
    localStorage.setItem('deletedMarkers', JSON.stringify(deletedMarkers));
    
    // Get the marker and remove it from the map
    let marker = markerObjects[markerId];
    if (marker) {
        marker.closePopup();
        %s.removeLayer(marker);
    }
}

// Initialize markers when page loads
document.addEventListener('DOMContentLoaded', initMarkers);
</script>
""" % (json.dumps(markers_data), m.get_name(), m.get_name())

# Add the script to the map
m.get_root().html.add_child(folium.Element(js_code))

# Save the map
m.save('persistent_markers.html')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants