dcc.Input changes output but can it not?

Hi,

Is it possible, to have input cells and an ‘update’ button such that the user can change the input cell data but the output table only changes once the ‘update’ button has been clicked?

Right now the output table changes with a change in the input cell but I don’t want that.

Hello @dgudhka,

Sure, instead of your inputs being Inputs in the callback, change them to be State. :slight_smile:

It says both html and dcc have no attribute State

Should be something like this:

@app.callback(Output("output", "graph"),
 Input("button", "n_clicks"),
 State("input1","value"),
 State("input2","value"))
1 Like

You also need to import State if you haven’t already. On your line at the top of your file when you import the other dash components you need to include State

from dash import html, dcc, Input, Output, State

Don’t forget to include any other dash imports you already have in your file.

1 Like

Ahh I see! It works in the callback. Thanks for the example!

1 Like

Additionally, is there a way to have the old output remain on screen while the new output loads with the spinner and then have the old output change to a new output (table) once the loading is complete?

We have no clue how you’ve structed stuff thus far but when you say Spinner I presume this means your using dcc.Loading?

When you use dcc.Loading it’s going to have the spinner replace the table while it’s loading the component.

You probably could had a dcc.Loading be a separate component, for example on your button.

Then you could have the Datatable be it’s a component outside of any callback and have a callback that feeds the datatable the the records to populate the table.

Then your function that loads data is separate from what turns the data into the data records to display in the datatable.

Then button is clicks, loader triggers on the button so the user can see something is happening, and the table is just sitting there displaying the old data until the new data returns from the callback and updates the table.

1 Like
    # lets user update data themselves    
    # loading button
    dbc.Spinner(children=[html.Button('Update', id='interval-component',style = {'marginLeft':'10px'}),
                          html.Div(id='page-1-content')
                         ], color = 'rgb(0,128,0)'),
])

# callback takes in 4 input variables including one to refresh every 15 seconds
@callback(
    Output('page-1-content','children'),
        [
    State('dropvalue','value'),
    State('datevalue','value'),
    State('notional','value'),
    Input('interval-component', 'n_clicks')
        ])

# datatable is using the dataframe from the query  
def update_output(dropval,dateval,notional,n):

This is my code. I must have the Datatable being generated in the callback as the user gets to define the dataframe with a SQL pull based on input parameters. As of now my dbc.Spinner is a loading button that replaces any data on the screen until newer data is generated. I want to keep the old data with the loading button, if possible.

Have you tried what I suggested?

Don’t return the full data table, just return the data from the callback and have the data feed into the data table.

@callback(
    Output('table-name', 'data'),
    Input('input1', 'value'),
)
def update_table(input1):
    #Do the data processing/SQL pull etc below
    df = pd.read_sql()
    return df.to_dict('records')

Then higher up in your app have the data table

table_content = dash_table.DataTable(
                        id='table-name',
                        data=[],
                        columns=[{"name": i, "id": i} for i in df.columns],
                    )

Then just add the table_content to your app layout

app.layout = html.Div([
                dcc.Dropdown(['1', '2', '3'], id='input1'),
                table_content
)

Then as I mentioned previously only put the spinner on the button don’t include it on the datatable.

1 Like

Hi,

I agree - I think this is how it will work.

But when I try to put the following code before the app.layout or before the callback it says df not defined and table_content not defined respectively:


table_content = dash_table.DataTable(
                        id='table-name',
                        data=[],
                        columns=[{"name": i, "id": i} for i in df.columns],
                    ) 

Which is fair because I am unsure as to where the df is being defined initially in table_content when data =

If instead I try to put table_content inside app layout it wont allow defining it.

Could you provide some advice on where exactly this code above should go or direct me to a working example?

My post above shows you all the things you would need to add, just to confirm did you add all 3 parts? If you didn’t do all parts and only did the one you copy pasted it’s not going to work without the rest.

For the columns that’s my mistake you can delete the column line completely you do not need to define the column names when you’re returning the data as records. Alternatively you can manually define each column and it’s data type. Manually defining will give you more fine control of the data table but obviously is a bit more work.

It explains all of this in the Datatable documentations:

Here’s a sample app to return data from callback to dataframe. As noted there’s may changes you’ll need to make to work with your application layout like the button spinner and such. But this is the callback logic to pass data to the table. How I set it up will display the full DF in the datatable when no dropdown is selected, then if you pick one of the fruits in the dropdown the table filtered down to that fruit only.

from dash import Dash, dcc, html, dash_table, Input, Output, State
import pandas as pd

app = Dash(__name__)


app.layout = html.Div([
                dcc.Dropdown(['Apples','Oranges','Bananas'], id='input1'),
                dash_table.DataTable(
                        id='table-name',
                        data=[],
                    )
])


@app.callback(
    Output('table-name', 'data'),
    Input('input1', 'value'),
)
def update_table(input1):
    #Do the data processing/SQL pull etc below I will just use a sample df for the example:
    df = pd.DataFrame({
        "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
        "Amount": [4, 1, 2, 2, 4, 5],
        "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
        })
    if input1: 
        df = df[df['Fruit']==input1]
        return df.to_dict('records')
    else:
        return df.to_dict('records')



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

Thanks
Payton

1 Like