Implementing button to delete an input field Dynamic Callback

Hello all,
I m newbie in Plotly And I would like to have some help.
I m trying to add a pushbutton that deletes the filter that i add with the button add filter. And I didn’t succeed :confused:


here is the line that I m using

 if deleteclick==None:
    new_children = html.div([...])
    children.append(new_children)
else : 
    children.pop()
    deleteclick= None

I have already read this documentation Pattern-Matching Callbacks | Dash for Python Documentation | Plotly and it didn’t really help me

Here’s an example for adding and removing graphs. This should help you do the same with filters.

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Div(children=[
        html.Button(
            'Add Chart', id='add-chart', n_clicks=0,
            # style={'display': 'inline-block'}
        ),
    ]),

    html.Div(id='container', children=[]),
    html.Button('Remove Chart', id='remove-chart', n_clicks=0),
])


@app.callback(
    Output('container', 'children'),
    [Input('add-chart', 'n_clicks'),
     Input('remove-chart', 'n_clicks')],
    [State('container', 'children')],
    prevent_initial_call=True
)
def display_graphs(add_clicks, remove_clicks, div_children):
    ctx = dash.callback_context
    triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if triggered_id == 'add-chart':
        new_child = html.Div(
            children=[
                dcc.Graph(
                    id={
                        'type': 'dynamic-graph',
                        'index': add_clicks
                    },
                    figure={}
                ),
            ]
        )
        div_children.append(new_child)

    elif triggered_id == 'remove-chart' and len(div_children) > 0:
        div_children = div_children[:-1]

    return div_children
2 Likes

It works perfectly :slight_smile: Thanks a lot.
Can you explain me what

ctx = dash.callback_context
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]

is doing.
keep on making good video quality :slight_smile:

Hi Yacine,

We have two inputs, so it helps determine which input was clicked on by user. See this document for a deeper explanation, under the section “Determining which Input has fired with…”

https://dash.plotly.com/advanced-callbacks

1 Like

Hi @adamschroeder thanks the reply. In my project I want to delete any intermediate elements using delete button. Can you please point me out where I can look for helper code?

For now I am trying to publish new_child containing remove-filter button when the add-filter button is clicked. Here drawback is that I can not use add-filter and remove-filter
as Inputs in the same callback. But I can not use two different callbacks with these Inputs either, because Output from these callback would point to a single element (“container”, “children”).

Can you please help me here? That would be greatly appreciated.

Thanks!

Hi @Push ,
I’m not sure I fully understand what you’re trying to accomplish. Can you please share some code with me. Show me what you have so far.

Hi @adamschroeder I would but there is not much difference in the code compare to what you suggested in your comment. The problem is that current implementation of callback allows us to delete the latest/ or last element of div_children. But I am interested to make any intermediate element from div_children disappear using remove button. For your reference please visit this GitHub page where code exists. Thank You.

Hi @Push
this code that I just wrote seemed to work for me. Play around with it and let me know if you encounter any bugs.

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

app = dash.Dash(__name__, suppress_callback_exceptions=True)

app.layout = html.Div([
    html.Div(children=[
        html.Button(
            'Add Chart', id='add-chart', n_clicks=0,
        ),
    ]),

    html.Div(id='container', children=[]),
])


@app.callback(
    Output('container', 'children'),
    Input('add-chart', 'n_clicks'),
    Input({'type': 'remove-btn', 'index': ALL}, 'n_clicks'),
    [State('container', 'children')],
    prevent_initial_call=True
)
def display_graphs(add_clicks, n, div_children):
    ctx = dash.callback_context
    triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]

    elm_in_div = len(div_children)
    print("initial num of elements: {}".format(elm_in_div))

    if triggered_id == 'add-chart':
        new_child = html.Div(id={'type':'div-num', 'index':elm_in_div},
            children=[
                dcc.Graph(
                    id={
                        'type': 'dynamic-graph',
                        'index': elm_in_div
                    },
                    figure={}
                ),
                html.Button('Remove this chart', id={'type': 'remove-btn',
                                                     'index': elm_in_div})
            ]
        )
        div_children.append(new_child)
        return div_children

    if triggered_id != 'add-chart':
        for idx, val in enumerate(n):
            if val is not None:
                print(f"All the remove buttons: {n}")
                print(f"The index pertaining to the remove button clicked: {idx}")
                print(f"The number of time this particualr remove button was clicked: {val}")
                del div_children[idx]
                return div_children

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

Hi @adamschroeder , thanks for the code. Surely, I will play with it and let you know.

Hi @adamschroeder code works as I wanted. Thank you for your help! Really appreciated!