✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

How to create a a pop-up, modal, or confirm dialog when the file user upload is not a CSV file

I want to create a pop-up, modal, or confirm dialog when the file user upload is not a CSV file. Can anyone teach me how to do it?

Below is the code:

def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')
    decoded = base64.b64decode(content_string)
    if 'csv' in filename:
        # Assume that the user uploaded a CSV file
        return pd.read_csv(
            io.StringIO(decoded.decode('utf-8')))

Checkout dash-bootstrap-component’s Modal component here. If your parse_contents def is assoc. with a callback, you can add the modal’s is_open property to it’s output… You can use Dash/Plotly to create modal but it’s more work…but dash-bootstrap-components make it so much easier.

if 'csv' in filename:
  # 2nd return value assoc. with is_open
  return pd.read_csv(...), False
else:
    # could return empty pd, dash.no_update
   return ??, True

Hi, @flyingcujo, my parse_content def is not assoc with a callback, so I don’t know how to call the bootstrap Modal I created.

Below is the code I write for the upload component that creates a data table.

import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table

import pandas as pd


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

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    dcc.Upload(
        id='datatable-upload',
        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

    ),
    html.Div(id='output-data-upload'),
])


def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')
    decoded = base64.b64decode(content_string)
    if 'csv' in filename:
        # Assume that the user uploaded a CSV file
        return pd.read_csv(
            io.StringIO(decoded.decode('utf-8')))
    elif 'xls' in filename:
        #Assume that the user uploaded an excel file
        return pd.read_excel(io.BytesIO(decoded))

@app.callback(Output('output-data-upload', 'children'),
               [Input('datatable-upload', 'contents')],
               [State('datatable-upload', 'filename')])
def update_output(contents, filename):
    if contents is None:
        return []
    df = parse_contents(contents, filename)
    return html.Div([
        dash_table.DataTable(
            id='table',
            style_data={
                'whiteSpace': 'normal',
                'height': 'auto'
            },
            style_table={'overflowX': 'scroll',
                         'maxHeight': '300',
                         'overflowY': 'scroll',
                         'maxWidth': '300'},
            style_cell={
                'minWidth': '150px', 'maxWidth': '180px',
                'whiteSpace': 'normal',
                'textAlign': 'left'
            },
            style_header={
                'fontWeight': 'bold',
            },
            fixed_rows={'headers': True, 'data': 0},
            columns=[{"name": i, "id": i, 'deletable': True, 'renamable': True} for i in df.columns],
            data=df.to_dict("records"),
            
        )
    ])



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

Here is a quick update to your code that shows modal. Noticed I changed your external_stylesheet to utilize dash-bootstrap-components…this may/may not affect your overall app development if you also rely on the other .css file.

import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import dash_bootstrap_components as dbc

import pandas as pd

# external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([
    dcc.Upload(
        id='datatable-upload',
        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

    ),
    html.Div(id='output-data-upload'),

    # Add Modal
    dbc.Modal(
        [
            dbc.ModalHeader("Your Header"),
            dbc.ModalBody("This is the content of the modal...file not XLS"),
            dbc.ModalFooter(
                dbc.Button("Close", id="close", className="ml-auto")
            ),
        ],
        id="modal",
        is_open=False,
    ),
])


def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')
    decoded = base64.b64decode(content_string)
    if 'csv' in filename:
        # Assume that the user uploaded a CSV file
        return pd.read_csv(
            io.StringIO(decoded.decode('utf-8')))
    elif 'xls' in filename:
        # Assume that the user uploaded an excel file
        return pd.read_excel(io.BytesIO(decoded))


@app.callback([Output('output-data-upload', 'children'),
               Output('modal', 'is_open')],
              [Input('datatable-upload', 'contents'),
               Input('close', 'n_clicks')],
              [State('datatable-upload', 'filename')])
def update_output(contents, modal_close, filename):
    ctx = dash.callback_context
    user_clicked = ctx.triggered[0]['prop_id'].split('.')[0]

    # If close button clicked, don't update datatable-upload contents (maybe you want too???) but close modal
    if not user_clicked or user_clicked == 'close':
        return dash.no_update, False

    if contents is None:
        return [], False

    if not filename.endswith(('.xls', '.csv')):
        return [], True

    df = parse_contents(contents, filename)
    return html.Div([
        dash_table.DataTable(
            id='table',
            style_data={
                'whiteSpace': 'normal',
                'height': 'auto'
            },
            style_table={'overflowX': 'scroll',
                         'maxHeight': '300',
                         'overflowY': 'scroll',
                         'maxWidth': '300'},
            style_cell={
                'minWidth': '150px', 'maxWidth': '180px',
                'whiteSpace': 'normal',
                'textAlign': 'left'
            },
            style_header={
                'fontWeight': 'bold',
            },
            fixed_rows={'headers': True, 'data': 0},
            columns=[{"name": i, "id": i, 'deletable': True, 'renamable': True} for i in df.columns],
            data=df.to_dict("records"),
        )
    ]), False


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

Thank you @flyingcujo. That’s what I needed.