Dash table add row button only works for the first time

Hi,
I am trying to create interactive table with dash_table. I want to add rows to editable table (id=‘adding-rows-table’) referring to this link Editable DataTable | Dash for Python Documentation | Plotly. However, the add row button can only add one row to the table.
Could you help me with it? Thank you very much!

Jing

Here is my script:

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import dash_table as dt
import pandas as pd
from collections import OrderedDict


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

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
app.scripts.config.serve_locally = True
app.css.config.serve_locally = True

df = pd.DataFrame(OrderedDict([
    ('company_name', ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D', 'D']),
    ('De1', [10,10,10,9,9,8,8,7,7]),
    ('De2', [20,20,20,19,19,18,18,17,17]),
    ('De3', ['AA', 'AA', 'AA', 'BB', 'BB', 'CC', 'CC', 'DD', 'DD']),
    ('Fee_code', ['#1','#2','#3','#4','#5','#6','#3','#1','#2']),
    ('Fee', [10,11,12,13,14,15,16,17,18]),
    ('Volumn', [19,20,21,22,23,24,25,26,27])
]))

df_empty = pd.DataFrame(OrderedDict([
    ('Fee_code', []),
    ('Fee', []),
    ('Volumn', [])
]))

def create_table(data1):
    table = dt.DataTable(
                data=data1.to_dict('records'),
                columns=[{"name": i,"id": i} for i in data1.columns],
                style_cell={'textAllign': 'center','min-width':'50px'}
            )
    return table


dropdown_options = [{'label':i,'value':i} for i in df.company_name.unique()]
fee_list = [{'label':i,'value':i} for i in df.Fee_code.unique()]

app.layout = html.Div([
    #header
    html.Div([
        html.H1('Dashborad_V1')
    ],
    style = {'padding':'50px', 'backgroudColor': '#3aaab2'}),
    #dropdown
    html.P([
        html.Label('Choose a client'),
        dcc.Dropdown(
            id='dropdown',
            options=dropdown_options,
            value='Select a company'
        )], style = {'width':'400px', 'fontsize':'20px','padding-left':'100px','display':'inline-block'}),
    #tables
    html.Div([
        html.H1('Demographic information'),
        html.Div(id='de_table')
    ]),
    html.Div([
        html.H1('Base line'),
        html.Div(id='br_table')
    ]),
    html.Div([
        html.H1('Adjustable Fees'),
        dt.DataTable(
            id='adding-rows-table',
            data=df_empty.to_dict('records'),
            # columns=[{"name": i,"id": i} for i in df_br.columns if i != 'id'],
            columns=[
                {'id': 'Fee_code', 'name': 'Fee_code', 'presentation': 'dropdown',"deletable": False},
                {'id': 'Fee', 'name': 'Fee', "deletable": False},
                {'id': 'Volumn', 'name': 'Volumn'},
            ],
            editable=True,
            dropdown={
                'Fee_code': {
                'options': [
                        {'label': i, 'value': i}
                        for i in df['Fee_code'].unique()
                        ]
                }
            },
            row_deletable=True,
            sort_action='native',
            filter_action='native',
            row_selectable='multi',
            page_action='native',
            export_format='xlsx',
            export_headers='display',
            merge_duplicate_headers=True
        ),
        html.Button('Add Row', id='editing-rows-button', n_clicks=0),
        html.Button(id='submit-button', n_clicks=0, children='Submit')
    ]),
    html.Div([
        html.H1('Adjusted Recommendation'),
        html.Div(id='output_table')
    ])
])

@app.callback(
    [Output('de_table', 'children'), 
     Output('br_table', 'children')], 
    [Input('dropdown', 'value')]
    )
def build_selection(value):
    dff = df.loc[df['company_name'] == value]
    df_demo = dff[['company_name', 'De1', 'De2', 'De3']].drop_duplicates(subset=None, keep='first', inplace=False)
    df_br = dff[['Fee_code', 'Fee', 'Volumn']]
    return create_table(df_demo), create_table(df_br)


**@app.callback(**
**    Output('adding-rows-table', 'data'),**
**    [Input('editing-rows-button', 'n_clicks'),**
**    Input('dropdown', 'value')],**
**    [State('adding-rows-table', 'data'),**
**     State('adding-rows-table', 'columns')])**

**def add_row(n_clicks, value, rows, columns):**
**    rows = df_empty.to_dict('records')**
**    df_selected = df.loc[df['company_name'] == value]**
**    df_selected_fee = df_selected[['Fee_code', 'Fee', 'Volumn']]**
**    print(df_selected_fee)**
**    change = len(df_selected) -len(rows)**
**    if change >0:**
**        for i in range(change):**
**            rows.append({c["id"]: "" for c in columns})**
**    if n_clicks > 0:**
**        print('add!')**
**        rows.append({c['id']: '' for c in columns})**

**    rows[:len(df_selected)] = df_selected.to_dict('records')**
**    return rows**

@app.callback(
    Output('output_table', 'children'),
    [Input('adding-rows-table', 'data')])
def display_output(rows):
    out = pd.DataFrame(rows)
    print(out)
    return create_table(out)

application = app.server

if __name__ == '__main__':
    application.run(debug=True)

Same issue here. Did you ever figure it out?

just comment this line:

rows = df_empty.to_dict('records')

1 Like

Hi @mgrondier, I tried to build callback like this:

    @dashapp.callback(
        [Output('adj-de-table', 'data'),
        Output('adj-anci-table', 'data'),
        Output('adding-rows-table', 'data')],
        [Input('br-button', 'n_clicks'),
        Input('latest-button', 'n_clicks'),
        Input('current-button', 'n_clicks'),
        Input('editing-rows-button', 'n_clicks'),
        Input('save-button','n_clicks'),
        Input('dropdown', 'value'),
        Input('adj-dropdown', 'value'),
        Input('input-de','children'),
        Input('input-fee','children'),
        Input('saved records', 'children')],
        [State('adding-rows-table', 'data'),
        State('adding-rows-table', 'columns'),
        State('adj-de-table', 'data'),
        State('adj-anci-table', 'data'),
        State('prune_table', 'data')]
        )
    def adding_row(br, last_modification, current, add_row, save, selection, selected_adj, input_de, input_fee, adj_records, rows, columns, de_rows, anci_rows, prune_data): 
        ctx = dash.callback_context 
        changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0] 
       
        if 'editing-rows-button' in changed_id and selection is not None and input_de is not None and len(input_de)>0:
            rows = ctx.states['adding-rows-table.data']
            de_rows = ctx.states['adj-de-table.data']
            anci_rows = ctx.states['adj-anci-table.data']
            rows.append({c['id']: '' for c in columns})

It worked for adding many rows.

1 Like

Hi, jing0703 thanks for your post. I was wondering that by using your code, when you are adding a new row, do the cell will automatically with a dropdown list with it? Because I am working on a interactive table, I cannot add a new row with the a specific cell with a dropdown list for validating the input.