Hi, I’ve build a prototype webpage to use the url search params as input for a slider, and vice-versa. So if the url changes, the change should update the slider, and if the slider changes, the url should be updated. I have a working version, see below. But if I click on a icon in the Dash debug screen, it gives me an error ‘too much recursion’. What can I do to get rid of this error?
from dash import Dash, dcc, html, Input, Output, State, ctx, Patch
from urllib.parse import parse_qs, urlparse
import logging
logging.basicConfig(level=logging.INFO)
app = Dash(__name__)
# Define year range
YEARS = list(range(1990, 2026))
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
dcc.Store(id='store', data={'year': 2000, 'my_value': None}),
dcc.Slider(
id='year-slider',
min=min(YEARS),
max=max(YEARS),
step=1,
value=2000,
marks={str(year): str(year) for year in YEARS[::5]},
tooltip={"placement": "bottom", "always_visible": True}
),
html.Div(id='output'),
])
# Store <--> url
@app.callback(
Output('url', 'search'),
Output('store', 'data', allow_duplicate=True),
Input('url', 'search'),
Input('store', 'data'),
prevent_initial_call=True
)
def store_url_and_initial_value(url_search, current_data):
trigger_id = ctx.triggered[0]["prop_id"].split(".")[0]
if trigger_id == 'url':
params = parse_qs(urlparse(url_search).query)
year = params.get('year', [2000])[0]
logging.info(f"Trigger id is url, {year}")
value1 = f"?year={year}" # url
current_data = Patch()
current_data["year"] = year
value2 = current_data
return value1, value2
elif trigger_id == 'store':
year = current_data['year']
logging.info(f"Trigger id is store, {year}")
value1 = f"?year={year}" # url
current_data = Patch()
current_data["year"] = year
value2 = current_data
return value1, value2
else:
raise PreventUpdate
# Update slider <---> store
@app.callback(
Output('year-slider', 'value'),
Output('store', 'data', allow_duplicate=True),
Input('year-slider', 'value'),
Input('store', 'data'),
prevent_initial_call=True
)
def update_url_from_slider(year_slider, current_data):
logging.info(f"Slider <--> store {current_data}")
trigger_id = ctx.triggered[0]["prop_id"].split(".")[0]
if trigger_id == 'year-slider':
value1 = year_slider
current_data = Patch()
current_data["year"] = year_slider
value2 = current_data
return value1, value2
elif trigger_id == 'store':
value1 = int(current_data['year'])
current_data = Patch()
value2 = current_data
return value1, value2
else:
raise PreventUpdate
# Display the store data
@app.callback(
Output('output', 'children'),
Input('store', 'data')
)
def display_stored_data(store_data):
stored_data = store_data
return html.Div([
f"Current store: {stored_data}",
])
if __name__ == '__main__':
app.run(debug=True)