Upload to editable data table with callbacks

Hi again,

I’m currently trying to build my own version of an editable Table/Upload component with callbacks firing for upload and edit etc, mixing some of the example components given in the Dash documentation. That means, I need a predefined table when in which i inject the data from my uplaod. However I lack a complete understanding of the Data Table functionality it seems. Let me elaborate on this:

In the first example here

https://dash.plot.ly/dash-core-components/upload

the table is used in a way that injects the newly created table into the container element. First thing I do not understand: Why do we need this part in the original layout (see comment):

app.layout = html.Div([
    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=True
    ),
    html.Div(id='output-data-upload'),
    html.Div(dt.DataTable(rows=[{}]), style={'display': 'none'}) # THIS RIGHT HERE
])

The element that gets its child elements injected should be the output-data-upload, so the next div serves no apparent function whatsoever, because the parse_contents function injects the table into the upper div. But the whole thing doesnt work when we remove it.

Can anyone explain?

Also, why does this implementation not work? Like, at all. Doesn’t even print the callback except for once in the beginning.

import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt

import pandas as pd


app = dash.Dash()

app.scripts.config.serve_locally = True

app.layout = html.Div([
    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
    ),
    dt.DataTable(rows=[{}], id='upload-data-table', editable=True)
])


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')), sep=None,header=None)
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded), header=None)
    except Exception as e:
        print(e)
        return 'error'

    return df.to_dict('records')


@app.callback(Output('upload-data-table', 'rows'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename'),])
def update_output(content, name):
    print(content, name)
    return parse_contents(content, name)


app.css.append_css({
    'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})

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