Pass to dcc.input value in clientside/callback on button click

I created a generatable charts that saved in postgresql. I used For Loop in this. I added some buttons like a delete button for every charts. It look like this

My desired output is like this: If I clicked the delete button, get the value of dcc.input of that chart which is the ID from the postgresql and then call the charts model

ChartsModels().objects.get(id=value of dccinput).delete()

I’m open with any suggestion to improve my work.

app.layout = html.Div(id='graphs', children=[
])

@app.callback(Output('graphs', 'children'),
              Input('graphs', 'children'))
def update_extend_traces_traceselect(child):

    i = 0

        for b in barData:
                fig = go.Figure()
                fig.add_trace(
                    go.Bar(
                        x=[d['value'] for d in y][0],
                        y=newdatetime,
                        name=barname[i],
                        marker_color=barcolor[i],
                        orientation=orientation[i],
                        marker_line_color=markerlinecolor[i],
                        marker_line_width=float(markerlinewidth[i])
                    ))
            else:
                fig = go.Figure()
                fig.add_trace(
                    go.Bar(
                        y=[d['value'] for d in y][0],
                        x=newdatetime,
                        name=barname[i],
                        marker_color=barcolor[i],
                        orientation=orientation[i],
                        marker_line_color=markerlinecolor[i],
                        marker_line_width=float(markerlinewidth[i])
                    ))

            fig.update_layout(
                # barmode=barmode[i],
                xaxis_title=xtitle[i],
                yaxis_title=ytitle[i],
                title=title[i],
                showlegend=ast.literal_eval(showlegend[i]),
                xaxis_showgrid=ast.literal_eval(showgrid[i]),
                yaxis_showgrid=ast.literal_eval(showgrid[i]),
                xaxis_showticklabels=ast.literal_eval(showticklabels[i]),
                yaxis_showticklabels=ast.literal_eval(showticklabels[i])

            )

            child.append(html.Div(id="div-id", children=[dcc.Input(
                id="charts-id",
                type="text",
                value=chart_ID[i]
            ), html.Button('EDIT', id='edit-chart',
                           style={'margin': '5px'}),
                html.Button('Delete', id='hiddenButton', n_clicks=0,
                            style={'margin': '5px'}),
                dcc.Graph(figure=fig,
                          config={
                              'displayModeBar': False,
                          })],
                style={'height': '550px', 'width': '550px', 'margin': '10px',
                       'border': '1px solid'}))

            i = i + 1


app.clientside_callback(
    """
  function removeChart(n1, children) {
     console.log(n1)
return ''}
    """,
    Output('output_div', 'children'), Input(
        'hiddenButton', 'n_clicks'), State('graphs', 'children')
)

@app.callback(Output('output_div', 'children'),
             [Input('hiddenButton', 'n_clicks')],
                 [State('charts-id', 'value')],
               )
def update_output(clicks, input_value):
    if clicks is not None:
     print(clicks, input_value)

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

The problem it’s only getting the last value of dcc.Input. If I clicked the other delete button from other charts. It’s printing a None

Hi,

Here are two suggestions that might help you with this functionality in your app:

  1. The biggest problem in your layout so far is that you have repeated ids for all components that you are appending to the children. This can be fixed using a pattern matching callback, where you can use any index to identify the different components.

  2. If you follow the point above, then your clientside callback can be written using a MATCH pattern and you can simply return the entire “div-id” component children as an empty list, removing the chart and the buttons to edit and delete it. Just bear in mind that if you are adding new blocks with chart + buttons, you must assign a distinct index to the id and you must be careful not to trigger the edit and delete callbacks when adding the block (this is not prevented by prevent_initial_update.

I might be able to find a related example from the forum if needed (I don’t have any right now)…

@Chrollo,

Try this alteration:


app.layout = html.Div([html.Div(id='graphs', children=[
]),html.Button(id='hiddenButton', n_clicks=0)], id='page-content')

@app.callback(Output('graphs', 'children'),
              Input('graphs', 'children'))
def update_extend_traces_traceselect(child):

    i = 0

        for b in barData:
                fig = go.Figure()
                fig.add_trace(
                    go.Bar(
                        x=[d['value'] for d in y][0],
                        y=newdatetime,
                        name=barname[i],
                        marker_color=barcolor[i],
                        orientation=orientation[i],
                        marker_line_color=markerlinecolor[i],
                        marker_line_width=float(markerlinewidth[i])
                    ))
            else:
                fig = go.Figure()
                fig.add_trace(
                    go.Bar(
                        y=[d['value'] for d in y][0],
                        x=newdatetime,
                        name=barname[i],
                        marker_color=barcolor[i],
                        orientation=orientation[i],
                        marker_line_color=markerlinecolor[i],
                        marker_line_width=float(markerlinewidth[i])
                    ))

            fig.update_layout(
                # barmode=barmode[i],
                xaxis_title=xtitle[i],
                yaxis_title=ytitle[i],
                title=title[i],
                showlegend=ast.literal_eval(showlegend[i]),
                xaxis_showgrid=ast.literal_eval(showgrid[i]),
                yaxis_showgrid=ast.literal_eval(showgrid[i]),
                xaxis_showticklabels=ast.literal_eval(showticklabels[i]),
                yaxis_showticklabels=ast.literal_eval(showticklabels[i])

            )

            child.append(html.Div(id="div-id", children=[dcc.Input(
                id="charts-id",
                type="text",
                value=chart_ID[i]
            ), html.Button('EDIT', id='edit-chart',
                           style={'margin': '5px'}),
                html.Button('Delete', className="deleteButton",
                            style={'margin': '5px'}),
                dcc.Graph(figure=fig,
                          config={
                              'displayModeBar': False,
                          })],
                style={'height': '550px', 'width': '550px', 'margin': '10px',
                       'border': '1px solid'}))

            i = i + 1


app.clientside_callback(
    """
  function removeChart(n1, children) {
     console.log($(window.event.target).closest('input').val())
return $(window.event.target).closest('input').val()}
    """,
    Output('hiddenButton', 'children'), 
    Input('hiddenButton', 'n_clicks'),
    State('graphs', 'children')
)

@app.callback(Output('output_div', 'children'),
             [Input('hiddenButton', 'n_clicks')],
                 [State('hiddenButton', 'children')],
               )
def update_output(clicks, input_value):
    if clicks is not None:
     print(clicks, input_value)

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

You will need this in your js file as well.

$(document).ready(function() { setTimeout(function() {listenDelete()}, 1000)})

function listenDelete() {
    $(".deleteButton").on("click", function () {
    $("#hiddenButton").click()
    })
}

window.fetch = new Proxy(window.fetch, {
    apply(fetch, that, args) {
        // Forward function call to the original fetch
        const result = fetch.apply(that, args);

        // Do whatever you want with the resulting Promise
        result.then((response) => {
            if (args[0] == '/_dash-update-component') {
                setTimeout(function() {listenDelete()}, 2000)
            }
        })

        return result
    }
    })

Let me know if the second call gets your target div’s id. I cant really test this.