How to pass values between pages in dash

Hi, I am trying to create a dash where I have different pages. I am selecting one value on page 1. Then a message gets displayed- You have selected Value. Now I want that value to gets passed to Page 2, so that it says- You selected Value (Value on Page 1 using dropdown). But I am not able to do that. On running the dash, till Page 1, it works fine, but then on coming to Page 2, it shows updating.

Here is the code-

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

print(dcc.__version__)

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.config.suppress_callback_exceptions = True

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])


index_page = html.Div([
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
])


page_1_layout = html.Div([
    html.H1('Page 1'),
    dcc.Dropdown(
        id='page-1-dropdown',
        options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
        value='LA'
    ),
    html.Div(id='page-1-content'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
    html.Br(),
    dcc.Link('Go back to home', href='/'),
])

@app.callback(dash.dependencies.Output('page-1-content', 'children'),
              [dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
    return 'You have selected "{}"'.format(value)



page_2_layout = html.Div([
    html.H1('Page 2'),
    html.Div(id='page-2-content'),
    html.Br(),
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go back to home', href='/')
])

@app.callback(Output('page-2-content', 'children'),
              [Input('page-1-dropdown', 'value')])
def page_2(value):
    return 'You selected "{}"'.format(value)


# Update the index
@app.callback(dash.dependencies.Output('page-content', 'children'),
              [dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/page-1':
        return page_1_layout
    elif pathname == '/page-2':
        return page_2_layout
    else:
        return index_page


if __name__ == '__main__':
    app.run_server(debug=False,port=1244,host = '0.0.0.0')

I want to know how to go about this. Is there some way to store the value and make it accessible to page 2 because declaring the value as global in Page 1 is not helping. Please help.

2 Likes

Reading from and writing to a JSON or CSV file is what I’ve been doing, dash is pretty good with that

Try this:

index_page = html.Div(
# I added this id attribute
id='index_page',
children = [
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
],
# I added this style attribute
style={'height': '0px'}
)

page_1_layout = html.Div(
# I added this id attribute
id='page_1_layout',
children = [
    html.H1('Page 1'),
    dcc.Dropdown(
        id='page-1-dropdown',
        options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
        value='LA'
    ),
    html.Div(id='page-1-content'),
    html.Br(),
    dcc.Link('Go to Page 2', href='/page-2'),
    html.Br(),
    dcc.Link('Go back to home', href='/'),
],
# I added this style attribute
style={'height': '0px'}

)

page_2_layout = html.Div(
# I added this id attribute
id='page_2_layout',
children = [
    html.H1('Page 2'),
    html.Div(id='page-2-content'),
    html.Br(),
    dcc.Link('Go to Page 1', href='/page-1'),
    html.Br(),
    dcc.Link('Go back to home', href='/'),
],
# I added this style attribute
style={'height': '0px'}
)


app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content',
                       # I added this children attribute 
                       children=[index_page, page_1_layout, page_2_layout]
                )
])

# Update the index
@app.callback(
              [dash.dependencies.Output(page, 'children') for page in ['index_page', 'page_1_layout', 'page_2_layout']], # I turned the output into a list of pages
              [dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
    
    return_value = [{'height': '0px'} for _ in range(3)]

    if pathname == '/page-1':
        return_value[1] = {'height': 'auto'}
        return return_value
    elif pathname == '/page-2':
        return_value[2] = {'height': 'auto'}
        return return_value
    else:
        return_value[0] = {'height': 'auto'}
        return return_value

@app.callback(dash.dependencies.Output('page-1-content', 'children'),
              [dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
    return 'You have selected "{}"'.format(value)


@app.callback(Output('page-2-content', 'children'),
              [Input('page-1-dropdown', 'value')])
def page_2(value):
    return 'You selected "{}"'.format(value)

Basically, what I did here is that I loaded the pages all at once, and just hid the other pages by setting their div ‘height’ to 0.

Added benefit of this approach is that you won’t have to reload every page element when switching between pages. Also, all your selections in pages are retained.

Just inform me should this not work for you.

1 Like

Hi Thomas please tell me the code for the same.
Also the dash that I am building will have many users. So a lot of json and CSV files will not be feasible. Therefore is there any way by which the json/csv file gets generated upon selecting from the dropdown and then they are read at page 2. Furthermore, upon going back to dropdown on page 1, the previous json/csv file gets deleted ?

Hey Marlon,
The code doesn’t seems to work. Looks like the text got superimposed. please help.

Oww. Apologies. Try this:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

print(dcc.__version__)

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.config.suppress_callback_exceptions = True

index_page = html.Div(
    # I added this id attribute
    id='index_page',
    children=[
                dcc.Link('Go to Page 1', href='/page-1'),
                html.Br(),
                dcc.Link('Go to Page 2', href='/page-2'),
            ],
    # I added this style attribute
    style={'display': 'block', 'line-height':'0', 'height': '0', 'overflow': 'hidden'}
)

page_1_layout = html.Div(
    # I added this id attribute
    id='page_1_layout',
    children=[
        html.H1('Page 1'),
        dcc.Dropdown(
            id='page-1-dropdown',
            options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
            value='LA'
        ),
        html.Div(id='page-1-content'),
        html.Br(),
        dcc.Link('Go to Page 2', href='/page-2'),
        html.Br(),
        dcc.Link('Go back to home', href='/'),
    ],
    # I added this style attribute
    style={'display': 'block', 'line-height': '0', 'height': '0', 'overflow': 'hidden'}

)

page_2_layout = html.Div(
    # I added this id attribute
    id='page_2_layout',
    children=[
        html.H1('Page 2'),
        html.Div(id='page-2-content'),
        html.Br(),
        dcc.Link('Go to Page 1', href='/page-1'),
        html.Br(),
        dcc.Link('Go back to home', href='/'),
    ],
    # I added this style attribute
    style={'display': 'block', 'line-height': '0', 'height': '0', 'overflow': 'hidden'}
)

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content',
             # I added this children attribute
             children=[index_page, page_1_layout, page_2_layout]
             )
])


# Update the index
@app.callback(
    [dash.dependencies.Output(page, 'style') for page in ['index_page', 'page_1_layout', 'page_2_layout']],
    # I turned the output into a list of pages
    [dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
    return_value = [{'display': 'block', 'line-height': '0', 'height': '0', 'overflow': 'hidden'} for _ in range(3)]

    if pathname == '/page-1':
        return_value[1] = {'height': 'auto', 'display': 'inline-block'}
        return return_value
    elif pathname == '/page-2':
        return_value[2] = {'height': 'auto', 'display': 'inline-block'}
        return return_value
    else:
        return_value[0] = {'height': 'auto', 'display': 'inline-block'}
        return return_value


@app.callback(dash.dependencies.Output('page-1-content', 'children'),
              [dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
    return 'You have selected "{}"'.format(value)


@app.callback(Output('page-2-content', 'children'),
              [Input('page-1-dropdown', 'value')])
def page_2(value):
    return 'You selected "{}"'.format(value)


if __name__ == '__main__':
    app.run_server(debug=True, port=1244, host='0.0.0.0')


I hope you got the idea. :slight_smile:

6 Likes

It looks like you remain in the same page with three layouts and activate only one layout at a time based on the url.

I don’t think reloading pages helps at all. So, yours might be the only approach.

Hi @marlon, your solution works impeccably. I have a related question. Is there a way in dash to Duplicate tab or Open in a new tab so that values are retained from the original tab? Currently, when I use either of those options with your example, they are not.

To be more specific, I would like to open /page-1 in a new tab or duplicate page_1_layout with existing values.

style = {‘display’: ‘none’} should also work. Then I just use radio buttons to switch between layouts.

I think you can easily get the ‘children’ attribute of /page1 then output it into the ‘children’ attribute of the intended page (page_1_layout in your case).

I’m still waiting for a more elegant solution to this. I’ve tried dcc.Store component, but the problem is that only one callback can change his values (only one callback with Store Output), so sharing data between layouts is very limitated.

Callbacks dont work neither with inputs located in layouts in differents files.

The only solution to this is @marlon solution or dumping and reading constantly data to a json file. Am I right? Or does somebody has a better sol?

Take a look at this project. GitHub - jnguyen0220/dash-starter-kit: Dash plotly starter kit with routing and best practices

It uses the Id as global object that can be access in any pages that import app.py. you should be able to add the id in app.py and then access its state in any pages.