Data Availability inside of inactive dcc.Tab

Hi,

I’m struggling with updating data that is inside an inactive dcc.Tab which. Be default dcc.Tabs seem to inherit some sort of lazy loading that is only applied after the data containing tab is activated (opened) . A similar thread did not solve this issue yet.

In my application I’m trying to make dag.AgGrid rowData persistent, which is not natively supported. Therefore I’ve created callbacks that save the rowData in a local persistent dcc.Store that can be used to reload the grids. In my architecture the grids are in separate dcc.Tabs.
I am ultimately looking for a way to make the tabs update, even if they are not open (active). Of course, one could open and reload all tabs one after the other as a workaround but I don’t accept this yet as the only solution :smiley: In some other frameworks there is a renderActiveOnly option, so I think there should be more to it.

Here is my test app:


from dash import Dash, html, dcc, callback
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output, State
import dash_ag_grid as dag
import dash_bootstrap_components as dbc

app = Dash(__name__)

grid_1_col_defs = [
    {"headerName": "Type", "field": "type"},
    {"headerName": "Price", "field": "price"},
]

grid_1_row_data = [
    {"type": "Black tea", "price": 1},
    {"type": "Green tea", "price": 2},
]

grid_1 = dag.AgGrid(
    id="grid-1",
    columnDefs=grid_1_col_defs,
    rowData=grid_1_row_data,
)

grid_1_memory = dcc.Store(id="grid-1-memory", storage_type="local", data=[])


grid_2_col_defs = [
    {"headerName": "First name", "field": "first_name"},
    {"headerName": "Last name", "field": "last_name"},
]


grid_2_row_data = [
    {"first_name": "Peter", "last_name": "Griffin"},
    {"first_name": "Marge", "last_name": "Simpson"},
]

grid_2 = dag.AgGrid(
    id="grid-2",
    columnDefs=grid_2_col_defs,
    rowData=grid_2_row_data,
)

grid_2_memory = dcc.Store(id="grid-2-memory", storage_type="local", data=[])

app.layout = html.Div(
    [
        dbc.Button("Add row to grids", id="btn-add-row"),
        dbc.Button("Reload grids", id="btn-reload-grids"),
        dbc.Button("Show memory", id="btn-show-memory"),
        dcc.Tabs(
            [
                dcc.Tab(label="Tab 1", children=grid_1),
                dcc.Tab(label="Tab 2", children=grid_2),
            ],
        ),
        html.Div(id="memory-output"),
        grid_1_memory,
        grid_2_memory,
    ]
)


@callback(
    Output("grid-1", "rowTransaction"),
    Output("grid-2", "rowTransaction"),
    Input("btn-add-row", "n_clicks"),
    prevent_inital_call=True,
)
def add_row(n_clicks):
    if n_clicks:
        return {"add": [{"type": "Jasmin tea", "price": 3}]}, {
            "add": [{"first_name": "Donald", "last_name": "Duck"}]
        }
    else:
        raise PreventUpdate


@callback(
    Output("grid-1-memory", "data"),
    Output("grid-2-memory", "data"),
    Input("grid-1", "rowData"),
    Input("grid-2", "rowData"),
    prevent_inital_call=True,
)
def save_memory(_grid_1_row_data, _grid_2_row_data):
    return _grid_1_row_data, _grid_2_row_data


@callback(
    Output("grid-1", "rowData"),
    Output("grid-2", "rowData"),
    Input("btn-reload-grids", "n_clicks"),
    State("grid-1-memory", "data"),
    State("grid-2-memory", "data"),
    prevent_inital_call=True,
)
def reload_grids(n_clicks_reload, grid_1_memory_data, grid_2_memory_data):
    if n_clicks_reload:
        return grid_1_memory_data, grid_2_memory_data
    raise PreventUpdate


@callback(
    Output("memory-output", "children"),
    Input("btn-show-memory", "n_clicks"),
    State("grid-1-memory", "data"),
    State("grid-2-memory", "data"),
    prevent_inital_call=True,
)
def show_memory(n_clicks_show, grid_1_memory_data, grid_2_memory_data):
    if n_clicks_show:
        grid_1_memory_str = "\n".join([f"\t{row}" for row in grid_1_memory_data])
        grid_2_memory_str = "\n".join([f"\t{row}" for row in grid_2_memory_data])
        return html.Pre(
            f"Grid 1 memory:\n{grid_1_memory_str},\nGrid 2 memory:\n{grid_2_memory_str}"
        )
    else:
        raise PreventUpdate


if __name__ == "__main__":
    app.run_server(debug=True, port=1234)

peek1
peek2

As you can see, when adding a row to both grids, they are only really added, when the tab in which they are stored is activated.

Hi @luggie ,

That doesn’t solve your problem directly, but using dbc.Tabs (from dash_boostrap_compontents) instead of dcc.Tabs actually works.
I tested it, and it has the behavior that you are looking for.

thanks! I’ll take this as a “solution” :slight_smile:

1 Like