✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Layout does not change on multipage, but the url changed

I created multipage app, user will upload file on landing page that will redirect to another page.
The file will be converted to pandas dataframe and store in hidden div.
Then i am trying to fill dropdown option based on that dataframe immediately.

This process just need to run once, so callback must get input from hidden div children, but layout get stuck not change even after url changed. why ?

Alternatively, i can make callback get input from dropdown value change, and receive data from state of hidden div, but it will triggered each time user change dropdown value, which is unnecessary.

Here my code so far:

import base64
import dash
from dash.dependencies import Output, Input, State
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import custom_parser

# LAYOUTS
home = html.Div([
    html.H1('Landing Page'),
    dcc.Upload(id='upload-data', children=html.Div(['Drag and Drop or ', html.A('Select Files')]))])

anotherpage = html.Div([
    html.H1('Another Page'),
    dcc.Dropdown(id='dropdown', options=[], multi=True)])

# APP
app = dash.Dash()
server = app.server
app.config.suppress_callback_exceptions = True

# CALLBACKS
@app.callback([Output('url', 'pathname'), Output('data-store', 'children')], [Input('upload-data', 'contents')])
def upload_data(contents):
    if contents:
        _, content = contents.split(',')
        content_decoded = base64.b64decode(content)
        df = custom_parser.parse(content_decoded) # convert byte of string to pandas dataframe
        return '/anotherpage/', df.to_json(date_format='iso', orient='split')
    else:
        return dash.no_update, dash.no_update

# This callback not working, layout stuck on landing page, but url change, dont know why
@app.callback(Output('dropdown', 'options'), [Input('data-store', 'children')])
def fill_dropdown_options(df):
    df = pd.read_json(df, orient='split')
    dropdown_options = [{'label': i, 'value': i} for i in df.category.unique()]
    return dropdown_options

# This callback work, but will unnecessary triggered each time user change dropdown value
# @app.callback(Output('dropdown', 'options'), [Input('dropdown', 'value')], [State('data-store', 'children')])
# def fill_dropdown_options(dropdown_value, df):
#     df = pd.read_json(df, orient='split')
#     dropdown_options = [{'label': i, 'value': i} for i in df.category.unique()]
#     return dropdown_options

# INDEX
app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content'),
    html.Div(id='data-store', style={'display': 'none'})])

@app.callback(Output('page-content', 'children'), [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/':
        return home
    elif pathname.startswith('/anotherpage/'):
        return anotherpage
    else:
        return '404'

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