Refresh a component depending on changes in the database

Hi everyone,

I would like to know if there is a way to create a callback that refreshes each time a change occurs in a table in my database.

More precisely, the idea is to generate a list of data with a delete button for each line, and as soon as we click on the delete button, the line disappears.

I don’t know if it’s possible to do it on dash, my company needs this.

@app.callback(
    Output('successions-results', 'children'),
    [Input('dropdown-changes-career', 'value')])
def show_seccessions_results(input_name):
    id_profil = get_id(input_name)
    succession_plan = read_rows(TABLE_SUCCESSION_PLAN, id_profil)
    db = read_table(TABLE_REF_POSTES)
    dict = {key: value for key, value in zip(db['id_ref_job'], db['job_name'])}
    ref_jobs = succession_plan['id_ref_job'].map(dict).tolist()
    successions = (succession_plan[['< 1', '2-4', '>5']] == 1).idxmax(axis=1).values
    print(successions, ref_jobs)
    result = []
    for ref_job, succession, i in zip(ref_jobs, successions, range(succession_plan.shape[0])):

        result.append(dbc.Row([
            dbc.Col(ref_job),
            dbc.Col(succession),
            dbc.Col(dbc.Button("Delete",id=f"index-{i}", color="primary", className="me-1"))
        ]))
    return result

The code above only allows me to display the result, but I have no idea how to update the list based on click events.

Hi @Salah!

I believe that it is possible to do what you want with dash. To get to that point you need to solve/code two different things:

  1. Event-triggered callback: what you want is the callback to be responsive to a user interaction with a button. Interacting with a button typically involves using Input('id-button', 'n-clicks') + some State() argument. You can learn more about how to define this kind of callbacks in the ‘Dash App With State’ example here.

  2. Variable number of inputs that get updated (keeping the previous state): Okay so this part is trickier because it involves pattern-matching callbacks. Pattern-matching callbacks are the typical solution when you have a variable number of inputs. In your case, the variable number of inputs would be the list of IDs that have been selected in the dropdown and that can be removed from the list (BUT keeping the rest of the IDs that have been added and not deleted).

Your ‘goal app’ would be something similar to the Todo App example of the pattern-matching callbacks docs (yep, it’s the same link as before), at least in the definition of the arguments of the callback.

To understand this type of callbacks you should keep in mind that:

  • When you use Input()+State() the values of the components are specified with State(). Input() specifies when the callback is triggered. For example, with Input you typically specify the button activity (‘I want the callback to trigger when the user hits Delete’), and with State you typically specify what is going to be changed (‘I want this ID to be removed from the list of IDs’).

  • In order to keep the rest of the items (the ones that the user doesn’t delete) you need to both read and rewrite the content of the list. in the callback. In code language that would be: you need to give the children of the html component (‘successions-results’) as both and State (NOT as an input) and as an Output. In the State definition is where you would use the pattern-matching. If you check the Todo List example that I linked before, you will find this part in these lines of the callback definition:

@app.callback(
[
Output(“list-container”, “children”)

State({“index”: ALL}, “children”)
]

I know it’s a lot of information but I hope it helps you solve your problem. The first time you try to code it is the hardest and it will probably take some time and errors, but once you understand it, it will get easier (and quite useful) , I promise :muscle:

2 Likes

Actually, there might be a simpler solution. I guess from the id of your input that you are using a dcc.Dropdown component, so maybe you could use the multi = True argument instead of the pattern-matching callback: https://dash.plotly.com/dash-core-components/dropdown

In that case, you wouldn’t need to use a ‘Delete’ button or the State() argument because the list of the selected IDs will be updated automatically as the value of the dropdown. However:

  • You should change the body of your function to get several IDs at the same time instead of only one. I don’t know if that’s possible since I guess you are using custom functions (i.e. get_id). Maybe with a loop?
  • You should consider if this solution takes too much time as it would get all of the IDs’ data from the database in each update of the callback. Maybe this could help but I’m not an expert on clientside callbacks so I’m not sure: https://dash.plotly.com/dash-core-components/store
1 Like

Hi everyone,

I would like to thank you all for your replies. Actually the only point to keep in mind is that the list that i would like to view and edit is retrieved directly from a table in my database and and the dropdown is only there to select the person concerned and to retrieve the lines that correspond to him in the table.
Fortunately, I was able to draw inspiration from the todo example as suggested by @celia and I ended up with something quite similar to what I was looking for.

1 Like