rendering dynamic components with inputs that exist on the page
bakirillov opened this issue · 13 comments
Hello.
Doesn't work when is rendered in a tab.
Example:
elif tab == "tab-2":
return(
html.Div([
dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict("rows"),
)
])
)
df is empty DataFrame with 5 columns.
When "tab-2" is selected, the tab changes but the contents of previously selected tab remain.
Could you please look into that?
Also when I override that as suggested in plotly/dash#230 I am unable to show new data in that DataFrame.
Can you upgrade to the latest version of Dash? This should be fixed in 0.29.0: https://github.com/plotly/dash/blob/master/CHANGELOG.md#0290---2018-11-06.
I'm on 0.30.0 so new version does not help.
Also can't select or filter rows despite row_selectable="single" and filtering=True.
OK thanks for checking. Can you create a complete, minimal, reproducable example?
That should be complete example: https://gist.github.com/bakirillov/1c2e838ab70e0248a98b69651760385a
Also FYI:
Dash version: 0.30.0
Dash Table version: 3.1.6
Dash Core Components version: 0.37.2
Dash HTML Components version: 0.13.2
Thanks, taking a look now
It looks like this is actually more of an issue with dash-renderer
than the table component. In particular, its an issue with callbacks updating components that don't exist on the page yet: in your example, the DataTable
isn't renderered and therefore doesn't get the update from the callback.
Ideally, I think the correct way to solve this would be through having a global store and for that global store to update components as they get rendered. Here's a quick modification of your example:
import dash
import dash_table
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, State, Output
import json
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Minimal tab error example"
app.layout = html.Div([
dcc.Tabs(id="tabs", value="tab-1", children=[
dcc.Tab(label="Some tab", value="tab-1"),
dcc.Tab(label="Second tab", value="tab-2")
]),
html.Div(id='table-store'),
html.Div(id="tabs-content")
])
app.config['suppress_callback_exceptions']=True
@app.callback(
Output("tabs-content", "children"),
[Input("tabs", "value")])
def render_content(tab):
df = pd.DataFrame(
{"A":[1,2,3], "B": [1,2,3]},
columns=["A", "B"]
)
if tab == "tab-1":
return(
html.Div([
"Dash version: "+dash.__version__, html.Br(),
"Dash Table version: "+dash_table.__version__, html.Br(),
"Dash Core Components version: "+dcc.__version__, html.Br(),
"Dash HTML Components version: "+html.__version__,
html.Button("Change the data in the table", id="gobutton")
])
)
elif tab == "tab-2":
return(
html.Div([
dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict("rows"), sorting=True, row_selectable="single",
filtering=True
)
])
)
@app.callback(
Output("table-store", "children"),
[Input("gobutton", "n_clicks")]
)
def on_click(n_clicks):
df = pd.DataFrame(
{"A":[5,6,7], "B": [5,6,7]},
columns=["A", "B"]
)
if n_clicks:
return json.dumps(df.to_dict("rows"))
@app.callback(
Output("table", "rows"),
[Input("table-store", "data")]
)
def update_rows(rows):
print(rows)
return json.loads(rows)
if __name__ == '__main__':
app.run_server(debug=True)
However, dash-renderer
doesn't take into account existing components dependencies when renderering new ones. That seems like a bug to me but it'll require some more careful consideration.
That did not solve anything. The example still doesn't work.
And I don't understand why I can neither select nor filter the table despite it being selectable and filterable.
Selecting and filtering worked with dash-table-experiments (without tabs).
That did not solve anything.
Sorry, I wasn't clear enough. I know that it doesn't solve anything - this is a bug in dash-renderer
that we need to fix in order for that example to work.
Ok, got it. Good luck!)
The example @chriddyp posted above had some errors, but those became obvious when I tried to run it just now, and after I fix them this all seems to work as you'd expect - so it looks to me as though this bug has been fixed accidentally sometime in the last 6 months? Here's the updated example, the table initially has data 1,2,3 but after clicking the update button in the other tab it has 5,6,7 when I switch back:
import dash
import dash_table
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import json
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Minimal tab error example"
app.layout = html.Div([
dcc.Tabs(id="tabs", value="tab-1", children=[
dcc.Tab(label="Some tab", value="tab-1"),
dcc.Tab(label="Second tab", value="tab-2")
]),
html.Div(id='table-store'),
html.Div(id="tabs-content")
])
app.config['suppress_callback_exceptions'] = True
@app.callback(
Output("tabs-content", "children"),
[Input("tabs", "value")])
def render_content(tab):
df = pd.DataFrame(
{"A": [1, 2, 3], "B": [1, 2, 3]},
columns=["A", "B"]
)
if tab == "tab-1":
return(
html.Div([
"Dash version: "+dash.__version__, html.Br(),
"Dash Table version: "+dash_table.__version__, html.Br(),
"Dash Core Components version: "+dcc.__version__, html.Br(),
"Dash HTML Components version: "+html.__version__,
html.Button("Change the data in the table", id="gobutton")
])
)
elif tab == "tab-2":
return(
html.Div([
dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict("records"),
sorting=True,
row_selectable="single",
filtering=True
)
])
)
@app.callback(
Output("table-store", "children"),
[Input("gobutton", "n_clicks")]
)
def on_click(n_clicks):
df = pd.DataFrame(
{"A": [5, 6, 7], "B": [5, 6, 7]},
columns=["A", "B"]
)
if n_clicks:
return json.dumps(df.to_dict("records"))
@app.callback(
Output("table", "data"),
[Input("table-store", "children")]
)
def update_rows(rows):
print(rows)
if not rows:
raise dash.exceptions.PreventUpdate
return json.loads(rows)
if __name__ == '__main__':
app.run_server(debug=True)
So I'm going to close this, but if you're still seeing this or a related problem please open a new issue in the main dash
repo, as we're merging dash-renderer
in there.