emilhe / dash-leaflet

MIT License
214 stars 40 forks source link

Popup Content doesn't update #229

Open MalcolmDrummond opened 8 months ago

MalcolmDrummond commented 8 months ago

Dynamically setting popup with position and content (by replacing in 'popup' LayerGroup) - position is updated on every click, but it seems change in content has no effect after first update. I can't use children as I need formatted html. Is this a bug or am I doing something wrong? Here's minimal code ...

from dash import Dash, html, Output, Input, State, callback
import dash_leaflet as dl
from operator import itemgetter

app = Dash()
app.layout = html.Div([
    dl.Map([
        dl.TileLayer(id='layer'),
        dl.LayerGroup([], id='popup'),
    ], center=[0, 0], zoom=1, style={'height': '50vh'}, id='map'),
])

@app.callback(Output('popup', 'children'), [Input('map', 'n_clicks'), State('map', 'clickData')])
def click_coord(n_clicks, clickData):
    if clickData:
        lat, lng = itemgetter('lat','lng')(clickData['latlng'])
        content=f"Click #: {n_clicks}<Br><Br>Lat: {'%1.5f' % lat}<Br>Lon {'%1.5f' % lng})"
        popup = [dl.Popup(position=[lat, lng], content=content)]
    else:
        popup = []
    return popup

if __name__ == '__main__':
    app.run_server(debug=True)
Floowey commented 8 months ago

I can confirm that I experience the same issue with dl.Tooltip(). I do in fact have my callback on Output("map", "children") and while the locations do change correctly, the associated tooltip never refreshes correctly. I confirmed this by simply having

map_children = []
map_children.append(dl.Marker(position=coord, children=[dl.Tooltip(content=f"{label}, {datetime.now().time()}")]))

in my callback and realising that the label and time shown never change, even if the coordinate does - and thus putting the wrong label to the marker location.

Floowey commented 7 months ago

@MalcolmDrummond I found a possible workaround for this.

The issue is not really within Tooltip, Popup or even dash-leaflet. It's react-leaflet in the background, where updateMarker() only updates position, icon and some other stuff, but not the children. I'm not sure under whose responsibility it would fall to make that update call for individual children nodes, but a possible workaround is to create an entirely new and different Marker object so that updateMarker() is not called in the background instead. In my case, the Tooltip didn't change when the location changed, so I passed in the position coordinates as the id of the Marker (or a hash thereof), but I guess you could also use the Tooltip content or completely randomize the id and you should always have the correct child. When I say tooltip, it should of course also apply to the Popup.

map_children.append(dl.Marker(id=str(coord), position=coord, children=[dl.Tooltip(content=f"str(coord")]

In your case you might go so far as to add an "id" to the popup, so it gets recreated instead of updating incompletely.

MalcolmDrummond commented 7 months ago

@Floowey - Thanks. Recreating with a new, unique id every time has been working for me.

Tristan-Lo commented 7 months ago

Works for me as well, thanks @Floowey