💸 Reduce costs by consolidating proprietary analytics & reporting software to open-source & Dash.
Challenge us to replace your analytics with Dash and reduce costs.

Dcc.upload component doesn't populate a datatable and fails silently

In my callback function, I have a listener for dcc.uploads contents. The function is invoked upon upload and returns a pandas dataframe which populates the datatable. However, upon upload the datatable is NOT rendered or populated. I made sure the pandas df exists in the callback function.

Here’s a semi-reproducible example/code -

# App Layout

app.layout = html.Div([

    html.H3("Post Covid-19 Tool"),

    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=False
    ),

    html.Div([

        dash_table.DataTable(
            id='emp-table',
            page_size = 14,
            sort_action='native',
            row_selectable='multi',
            filter_action='native',
            row_deletable=True,
            editable=True
        ),
    ])

])


# In[12]:

# file upload function
def parse_contents(contents, filename):

    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)

    try:

        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(io.StringIO(decoded.decode('utf-8')))

        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))

    except Exception as e:
        print(e)
        return None

    return df


# Return Datatable
@app.callback([Output('emp-table', 'data'),
               Output('emp-table', 'columns')],
              [Input('upload-data', 'contents')],
              [State('upload-data', 'filename')])
def render_table(contents, filename):

    if contents and filename:

        df_geo = parse_contents(contents, filename)

        columns = [{"name": i, "id": i} for i in df_geo.columns]

        data = df_geo.to_dict('records')

        # Debug
        print(df_geo.head())

        return (data, columns)

    else:

        return []


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