That’s a good question, sorry I forgot to include that part after I discovered it.
Yes, there is circularity in the above: comparison-dropdown.value [select_comparison()] > store-prev-comparisons.data [trim_dropdown()] > comparison-dropdown.value [select_comparison()]
.
The way to stop it is to observe that after trim_dropdown()
finishes you have comparison-dropdown.value == store-prev-comparisons.data
. So all you have to do is pass store-prev-comparisons.data
as a State()
to select_comparison()
, check for this equality, and PreventUpdate if it holds.
@app.callback([Output('store-prev-comparisons', 'data')],
[Input('comparison-dropdown', 'value')],
[State('store-prev-comparisons', 'data')])
def select_comparison(comparisons, prev_comparisons):
if len(comparisons) == 4:
# changes store-prev-comparisons which triggers above callback
return comparisons[0:3],
elif comparisons == prev_comparisons:
# this only happens if we just trimmed so don't do anything to break circularity
raise dash.exception.PreventUpdate
else:
# when <= 3 don't modify store-prev-comparisons and therefore don't trigger above
return dash.no_update
By the way, if you have other callbacks that respond to comparison-dropdown.value
to do something with the values you can add the following to keep them from responding when the limit is reached and the above trimming executes.
if len(comparisons) == MAX_COMPARISONS + 1 or comparisons == prev_comparisons:
raise dash.exceptions.PreventUpdate