Hi all,
I ran into a weird issue where the derived_virtual_data of one DataTable actually shows up as the derived_virtual_data of another DataTable!
My application is a quite complicated multi-tab monstrosity with querystrings to preserve the state and make the state shareable (can post some code on how to make shareable state-based urls if people are interested).
The problem only happens when you load the page with a certain state on a certain tab. The gif below shows the behaviour: the html.Div below the DataTable on Tab A actually displays the derived_virtual_data from Tab B and vice versa:
Once you adjust the data again with a callback (in this case from the dropdown) the issue fixes itself. However it ideally should already work on first load
Below is the code to reproduce. Any suggestions on how to fix?
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import dash_table
import pandas as pd
app = dash.Dash()
app.config['suppress_callback_exceptions']=True
def tab_a_layout(state, options, columns):
return html.Div([
dcc.Dropdown(id='tab_a_dropdown', options=[{'label': i, 'value': i} for i in options], value=state),
dash_table.DataTable(
id='tab_a_table',
columns=[{"name": i, "id": i} for i in columns],
editable=True,
sorting=True,
sorting_type="single",
row_selectable="single",
selected_rows=[],
),
html.Div(id='tab_a_output')
])
def tab_b_layout(state, options, columns):
return html.Div([
dcc.Dropdown(id='tab_b_dropdown', options=[{'label': i, 'value': i} for i in options], value=state),
dash_table.DataTable(
id='tab_b_table',
columns=[{"name": i, "id": i} for i in columns],
editable=True,
sorting=True,
sorting_type="single",
row_selectable="single",
selected_rows=[],
),
html.Div(id='tab_b_output')
])
def tabs_layout(tab):
return dcc.Tabs(id='tabs', value=tab, children = [
dcc.Tab(label='Tab A', id='tab_a', value='tab_a', children = tab_a_layout('A', ['A', 'B'], ['tab_a_col1', 'tab_a_col2'])),
dcc.Tab(label='Tab B', id='tab_b', value='tab_b', children = tab_b_layout('B', ['A', 'B'], ['tab_b_col1', 'tab_b_col2']))
])
app.layout = html.Div([
tabs_layout('tab_b')
])
@app.callback(
Output('tab_a_table', 'data'),
[Input('tab_a_dropdown', 'value')],
[State('tabs', 'value')])
def callback_a(dropdown_value, tab):
if dropdown_value=='A':
return pd.DataFrame({'tab_a_col1': ['A','A'], 'tab_a_col2':['A','A']}).to_dict('rows')
if dropdown_value=='B':
return pd.DataFrame({'tab_a_col1': ['B','B'], 'tab_a_col2':['B','B']}).to_dict('rows')
@app.callback(
Output('tab_a_output', 'children'),
[Input('tab_a_table', 'derived_virtual_data')],
[State('tabs', 'value')])
def callback_b(rows, tab):
return str(rows)
@app.callback(
Output('tab_b_table', 'data'),
[Input('tab_b_dropdown', 'value')],
[State('tabs', 'value')])
def callback_a(dropdown_value, tab):
if dropdown_value=='A':
return pd.DataFrame({'tab_b_col1': ['A','A'], 'tab_b_col2':['A','A']}).to_dict('rows')
if dropdown_value=='B':
return pd.DataFrame({'tab_b_col1': ['B','B'], 'tab_b_col2':['B','B']}).to_dict('rows')
@app.callback(
Output('tab_b_output', 'children'),
[Input('tab_b_table', 'derived_virtual_data')])
def callback_b(rows):
return str(rows)
if __name__ == '__main__':
app.run_server(debug=True)