Cannot disable button after clicking it, or dynamically set dcc.Dropdown() value

I have the following elements: A dcc.Dropdown(), a dcc.Textarea() for comments, and a “Save” button.

On page load, the dropdown is set to a previously saved value; the comments field is empty and the comments field and “Save” button are disabled.

If you change the dropdown value, the comments field and “Save” button are enabled (this works).

You can then “Save” your updated value (the comments field is optional if you wish to record why you changed the dropdown value).

When you “Save”, it should clear the comments field and set the comments field and “Save” button to disabled (essentially, restore the page-load state, with the only difference being that the dropdown value has changed). But this is not working.

Can anyone help me identify why I can’t correctly reset my UI state after hitting “Save”?

Here’s a boiled down version of my callback:

@app.callback(

  [Output('comments-textarea', 'value'), Output('comments-textarea', 'disabled'), Output('save-button', 'disabled')],

  [Input('some-dropdown', 'value'), Input('save-button', 'n_clicks')],

  [State('comments-textarea', 'value')]

)

def update_data(dd_value, save_btn_clicks, comments_value):

  ctx = dash.callback_context

  if not ctx.triggered:

    raise PreventUpdate

  

  # Save button was clicked

  if ctx.triggered[0]['prop_id'] == 'save-button.n_clicks':

    do_something_with_data(dd_value, comments_value)

    return '', True, True

  else:

    return comments_value, False, False

I should note that it doesn’t work even if I comment out do_something_with_data(dd_value, comments_value).

NEVERMIND!

Finally figured out that the problem lay elsewhere in my code. Kind of hard/long to explain, but basically, the “Save” button was inside a <div> that had was associated with another callback that was preventing the updates I wanted from going through.

I am trying to create a callback in which the submit button is disabled until all inputs are filled, in which case it would be enabled. I can see you mentioned here you did that successfully, would you mind sharing this?

Something like this should work for what you’re describing. I have the callback fire on “n_blur” so that it only fires when an input loses focus, rather than “value” which will cause the callback fire on every keystroke. This isn’t necessary, but, again, will greatly reduce the number of callbacks.

@app.callback(
  [
    Output("submit-btn", "disabled")
  ],
  [
    Input("input-1", "n_blur"),
    Input("input-2", "n_blur"),
    Input("input-3", "n_blur")  
  ],
  [
    State("input-1", "value"),
    State("input-2", "value"),
    State("input-3", "value")
  ]
)
def disable_submit_button(_blur_1, _blur_2, _blur_3, input_1_value, input_2_value, input_3_value):
  # If any of the inputs are empty, disable the submit button
  return not input_1_value or not input_1_value or not input_1_value
1 Like