Black Lives Matter. Please consider donating to Black Girls Code today.

Multi-tab dash app : `dcc.Store` component in different tabs and exchanging data between tabs

Question on using dcc.Store in multi-tab structure app. I’d like to persist / store data switching between tabs. My multi-page / tabs dash app structure looks like:

  • index.py
  • app.py
    • Tabs
      • tab1.py
        • subtab1.py
        • subtab2.py
      • tab2.py

index.py renders the layout of from each file depending on the selection.

app.layout = html.Div([

    # tabs
    html.Div([

        dcc.Tabs(

            id="tabs",
            vertical=True,
            className="mb-3",
            persistence=True,

            children=[


                 dcc.Tab(label="tab1", value="tab1",
                         children=[dcc.Tabs(id="subtabs", persistence=True, 
                            children=[dcc.Tab(label='subtab1', value='subtab1'),
                                      dcc.Tab(label='subtab2', value='subtab2')
                            ],

                    )
                 ]),
                 dcc.Tab(label="tab2", value="tab2"),

            ],
            
        )

        ],

        className="row tabs_div"

    ),

        

        # Tab content
        html.Div(id="tab_content"),

])

Now, I’d like to exchange component state / data between different subtabs. subtab1.py contains dcc.Graph and data-table and 'subtab2.py contains a series of dcc.Graph components.

Do I need to add dcc.Store component in both subtab1.py and subtab2.py to store individual components and read from them? I’d like to be able to read components state of subtab1.py in subtab2.py and other files.

As long as the dcc.Store is not added through the layout by a callback (like the render_content callback returns an html.Div in the dcc.Tabs tutorial https://dash.plotly.com/dash-core-components/tabs) then the content of the dcc.Store should be accessible from any callback triggered by any other element at any time (in this particular application). For example, you could put dcc.Store as a child of the parent div that you have assigned to app.layout, i.e.,

app.layout = html.Div([
    dcc.Store(id='my-store'),
    html.Div([...]),
    ....
])
1 Like

Thanks.

I defined dcc.Store in subtab1.py and not index.py, as I’d like to capture user selection and state of the application (graph + data-table) on user button click. However, when I attempt to read from the State of this dcc.Store, it fails and isn’t available in subtab2.py

subtab1. py 

# Store graph and data-table in dcc.Store component
@app.callback(Output("comps-store","data"),
             [
              Input("map-graph1","figure"),
              Input("comps-table","data"),
              Input("comps-button","n_clicks")
             ]
             )
def comp_store(map, table, n_clicks):

    # Store map-graph and data-table as dictionary.

     return {"map": map, "table": table, "price": "$25"}
subtab2.py 

# Callbacks
@app.callback([
                       Output("median", "value"),
                      ],
                      [
                       Input("submarket-select", "value")
                      ],
                      [
                       State("comps-store", "data")
                     ]
                   )
def datacard(submarket, store_data):

        if store_data:
            print("comps-store", store_data)

            return (store_data['price'])
Error: 

A nonexistent object was used in an `State` of a Dash callback. The id of this object is `comps-store` and the property is `data`. The string ids in the current layout are: [button-container, url, content, tabs, subtabs, page-content, tab_content, submarket-select, price-graph, market-graph]

The store can just be stored in the layout because users cannot interact with it directly. At the beginning of your application (app.py) you should have something like

app=dash.Dash(__name__)
app.layout=html.Div([
    dcc.Store(id='comps-store'),
    ... the rest of the elements ...
])
1 Like