Plotly Dash: How to reset the "n_clicks" attribute of a dash-html.button?

Issue

I have a basic datatable in plotly/dash. My goal is to upload (or print for the sake of the example…) after I press the upload-button.

The issue is, that I can’t figure out how to get the n_clicks attribute of the button back to zero. So what happens is that after I clicked the button for the first time it prints continuously whenever something changes (row added or number changed/added), but what I want is for it to print only once whenever I click the button.

This is the code:

import dash
from dash.dependencies import Input, Output, State
import dash_table
import dash_daq as daq

import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']


df = pd.read_csv('.../dummy_csv.csv')


app = dash.Dash(__name__)

app.layout = html.Div([
    html.Div(id='my-div'),

    dash_table.DataTable(
        id='adding-rows-table',
        style_data={
            'whiteSpace': 'normal',
            'height': 'auto'
        },
        style_table={
            'maxHeight': '800px'
            , 'overflowY': 'scroll'
        },
        columns=[
            {'name': i, 'id': i} for i in df.columns
        ],
        data=df.to_dict('records'),
        editable=True,
        row_deletable=True

    ),

    html.Button('+ Row', id='editing-rows-button', n_clicks=0),

    html.Button('Update', id='btn-nclicks-1', n_clicks=0 ),

])


@app.callback(
    Output(component_id='my-div', component_property='children'),
    [Input('btn-nclicks-1', 'n_clicks'), Input('adding-rows-table', 'data')]
)
def update_output_div(n_clicks, data):
    if n_clicks > 0:
        print(data)
        # n_clicks = 0
        # return n_clicks

    else:
        print("else loop")


@app.callback(
    Output('adding-rows-table', 'data'),
    [Input('editing-rows-button', 'n_clicks')],
    [State('adding-rows-table', 'data'),
     State('adding-rows-table', 'columns')])
def add_row(n_clicks, rows, columns):
    if n_clicks > 0:
        rows.append({c['id']: '' for c in columns})
    return rows


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

This the CSV:

a,b,c,d
1,1,5,1
2,2,5,1
2,33,6,2
3,4,6,2

And this is the "faulty" output.

Solution

You could use the dash.callback_context property to trigger the callback only when the number of clicks has changed rather than after the first click. See the section on "Determining which Button Changed with callback_context" in the Dash documentation. The following is an example of how you could update your callback.

@app.callback(Output(component_id='my-div', component_property='children'),
    [Input('btn-nclicks-1', 'n_clicks'), Input('adding-rows-table', 'data')])
def update_output_div(n_clicks, data):

    changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]

    if 'btn-nclicks-1' in changed_id:

        print(data)
        # n_clicks = 0
        # return n_clicks

    else:

        print("else loop")

Answered By – Flavia Giammarino

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published