Is there any recommended way to update a multi-input callback only on button click?

Hey all,

I’ve been working on a simulator little app and the way it works is the following: you fill a form, then you click the “Simulate” button and it provides the simulator result. I managed to initially hide the empty div and provide a result after the first button click. But, because the callback depends both on dbc.Button's n_click and the form’s values, afterwards if someone modifies the form, the simulation’s result will keep modifying even if there are no further clicks.

Couldn’t test this minimal code, but here you can see the gist of the matter:

layout = (dbc.Container(html.Div([

            html.Div([

                html.Div(dcc.Slider(id='slider-baths', min=1,
                                    max=6,
                                    value=1,
                                    step=1,
                                    marks={
                                        1: '1',
                                        2: '2',
                                        3: '3',
                                        4: '4',
                                        5: '5',
                                        6: '6+',
                                    })
                         )
            ]),
     
    dbc.Button('Simulate', id='simulation-button'),
    html.Div( id='simulator-result', style={'display': 'none'}),

])

))

Then the callback is something like this:

@app.callback([Output(component_id='simulator-result', component_property='children'),
               Output(component_id='resultado-simulador', component_property='style')],
              [Input(component_id='simulation-button', component_property='n_clicks'),
               Input(component_id='slider-baths', component_property='value'),

               ])
def get_prediction_sample(n_clicks,  n_baths):
    if n_clicks is None:

        style = {'display': 'none'}
        results_simulator= ''
    else:
        price = n_baths*2
        results_simulator = f'{price}'
        style = {'display': 'block'}

    return results_simulator, style

So, how should I be able to update my results only when n_clicks increases but not when slider-baths changes. I know callbacks have no memories from previous states, but from other posts I read, it seems there’s something that could be done to achieve my desired result. Do you have any ideas?

Hi, what I think is because you have 2 inputs. So, if any of those inputs change, then the callback will be triggered. I would recommend you instead 2 things:

  1. in dbc.Button('Simulate', id='simulation-button'),, add: n_clicks=0:

dbc.Button('Simulate', id='simulation-button',n_clicks=0)

With this, you will have n_clicks=0 as a number instead of "None"

  1. Change Input(component_id='slider-baths', component_property='value') for State:

State(component_id='slider-baths', component_property='value')

With this, you can read the same values and the callback will be triggered just when the button is pressed.

@app.callback([Output(component_id='simulator-result', component_property='children'),
               Output(component_id='resultado-simulador', component_property='style')],
              [Input(component_id='simulation-button', component_property='n_clicks')],
               [State(component_id='slider-baths', component_property='value')])
def get_prediction_sample(n_clicks,  n_baths):
    if int(n_clicks) > 0:

        style = {'display': 'none'}
        results_simulator= ''
    else:
        price = n_baths*2
        results_simulator = f'{price}'
        style = {'display': 'block'}

    return results_simulator, style

I just discovered the use of States and managed to do what I was looking for doing exactly what you suggested. Thanks anyways !

1 Like