I’m trying to update a Details component, and when I update it I want it to “close”. Assigning it’s open property to ‘False’ doesn’t work as expected, also replacing it with another Details with open = False also doesn’t seem to work as expected (nor just replacing the `Details without setting the open property).
Below is a toy dash for seeing the behaviour. The first three details-button pairs behave seemingly such that their first press works and alters the open state of the component and then never again after that -> not updating the Details components as I would expect. Then the final pair (4) adds the curve ball that it seems that all presses of the button will have an affect on the component -> this is how I would expect it to behave, but it is not in keeping with examples 1-3.
My aim is to replace a Details component with another and for it to be closed on update; in reality I’m doing this will a series of nested Details components replacing a Div’s children attribute and I’m observing that any level of the nested Details object which I have previously opened stay open on update of the Div’s children.
Any thoughts?
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
app = dash.Dash()
app.layout = html.Div([
html.Details([
html.Summary('Details'),
html.P('Content')
],
#open=True,
id='details'),
html.Button('Close details', id='button'),
html.Div([
html.Details([
html.Summary('Details2'),
html.P('Content2')
]),
],id='div2'),
html.Button('Replace 2 with new details', id='button2'),
html.Div([
html.Details([
html.Summary('Details3'),
html.P('Content3')
]),
],id='div3'),
html.Button('Replace 3 with new details set `open = False`', id='button3'),
html.Details([
html.Summary('Details4'),
html.P('Content4')
],id='details4'),
html.Button('Open/Close 4', id='button4'),
])
@app.callback(
Output('details', 'open'),
[
Input('button', 'n_clicks')
],
[
State('details', 'open')
])
def close_details(n_clicks, d_open):
if n_clicks:
print('Close 1')
return False
else:
return d_open
@app.callback(
Output('div2', 'children'),
[
Input('button2', 'n_clicks')
],
[
State('div2', 'children')
])
def new_details(n_clicks, children):
if n_clicks:
print('New 2')
details = html.Details([
html.Summary('Details2New'),
html.P('Content2New')
])
return [details]
else:
return children
@app.callback(
Output('div3', 'children'),
[
Input('button3', 'n_clicks')
],
[
State('div3', 'children')
])
def new_details_open_false(n_clicks, children):
if n_clicks:
print('New 3')
details = html.Details([
html.Summary('Details3New'), #removing the 'New' doesn't change behavior.
html.P('Content3New')
],open=False)
return [details]
else:
return children
@app.callback(
Output('details4', 'open'),
[
Input('button4', 'n_clicks')
],
[
State('details4', 'open')
])
def open_close_4(n_clicks, d_open):
if n_clicks:
if n_clicks % 2 == 0:
print('open 4')
return True
else:
print('close 4')
return False
else:
return d_open
if __name__ == '__main__':
app.run_server(debug=True)