I have a simple Dash app that reads an Excel file and populates a Dropdown based on data in the file. One possibility is that there is no data in the file and the Dropdown should be blank. I can create a blank Dropdown when initially building the page with this code:
html.Div(
id="feature-types",
children=dcc.Dropdown(
id="unique_features",
multi=True,
value=""
),
),
However, when using a callback targeted at Output(“feature-types”, “children”) if I attempt to return this same block of code I get a “Cannot read properties of null (reading ‘search’)” error at line 65 of Dropdown.react.js (this is triggered by the code that is rendering the component).
Here is my app (the input Excel file should have a worksheet called ‘Summary_Tab’ and a column headed ‘Unique_Features’. It works fine if that column has text data, but if the first row in NULL, I get the error.):
import dash
from dash import dcc, html, dash_table
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import pandas as pd
import plotly.graph_objs as go
from scipy.stats import norm
import base64
import os
import io
import math
sheet_to_df_map = None
app = dash.Dash(
external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.BOOTSTRAP],
suppress_callback_exceptions=True,
)
# Define UI
sidebar = dbc.Card(
[
dbc.Row( # Input File
[
dbc.Col(
[
dcc.Upload(
id="upload-data",
children=html.Div(["Drag & drop or click to select a file to upload."]),
style={
"width": "100%",
"height": "40px",
"lineHeight": "40px",
"borderWidth": "1px",
"borderStyle": "dashed",
"borderRadius": "5px",
"textAlign": "center",
"margin": "5px",
},
multiple=False,
accept=".xlsx",
),
dbc.Label(
id="file-list",
width={"size": 8, "offset": 2},
color="success",
style={"fontWeight": "bold"},
size="sm"
),
],
style={"maxWidth": "400px"},
),
]
),
dbc.Row( # Feature Types & ILI Run
[
dbc.Col(
[
dbc.Label("Feature types"),
html.Div(
id="feature-types",
children=dcc.Dropdown(
id="unique_features",
multi=True,
value=""
),
),
],
width={"size": 6},
),
],
),
],
body=True, color="#F3F3F3",
)
mainpanel = dbc.Card(
html.Div(
[
html.Div(id='output-data-upload'),
],
style={'width': '100%', 'display': 'inline-block', 'verticalAlign': 'top'}
),
className="border-0 bg-transparent"
)
app.layout = dbc.Container(
[
dbc.Row(
[
dbc.Col(sidebar, md=3),
dbc.Col(mainpanel, md=9),
],
align="top",
),
],
fluid=True,
)
def parse_contents(contents, filename):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded), sheet_name=None)
else:
return (None, html.Div(
[
'Please select a valid Excel file.',
dash_table.DataTable(
data=[{}],
columns=[{'name': "x", 'id': "x"}],
id='datatable'
),
]
))
except Exception as e:
print(e)
return (None, html.Div(
[
'There was an error processing this file.',
dash_table.DataTable(
data=[{}],
columns=[{'name': "x", 'id': "x"}],
id='datatable'
),
]
))
return (df, html.Div([
html.Div([dcc.Dropdown( id="field_dropdown",
options=[{
'label': i,
'value': i
} for i in df.keys()],
)],
style={'width': '25%', 'display': 'inline-block'}),
dash_table.DataTable(
data=[{}],
columns=[{'name': "x", 'id': "x"}],
id='datatable'
),
]))
@app.callback(
[Output("file-list", "children"), Output("output-data-upload", "children"),
Output("feature-types", "children")],
[Input("upload-data", "filename"), Input("upload-data", "contents")],
)
def update_output(uploaded_filenames, uploaded_file_contents):
global sheet_to_df_map
file_info = html.Div()
uf = dcc.Dropdown(
id="unique_features",
multi=True,
value=""
),
if uploaded_filenames is not None and uploaded_file_contents is not None:
sheet_to_df_map, file_info = parse_contents(uploaded_file_contents, uploaded_filenames)
if 'Summary_Tab' in sheet_to_df_map.keys() and 'Unique_Features' in sheet_to_df_map['Summary_Tab'].keys():
ufs = list(sheet_to_df_map['Summary_Tab']['Unique_Features'])
if ufs[0] != "nan":
uf = dcc.Dropdown(
id="unique_features",
options=ufs,
multi=True,
value=""
)
if uploaded_filenames is not None and len(uploaded_filenames) == 0:
return ([html.Div("No file selected")], file_info, uf)
else:
return (html.Div(uploaded_filenames), file_info, uf)
@app.callback(
[Output('datatable', 'data'), Output('datatable', 'columns')],
Input('field_dropdown', 'value'),
)
def update_datatable(user_selection):
return (
sheet_to_df_map[user_selection].to_dict('records') if user_selection is not None else None,
[{'name': i, 'id': i} for i in list(sheet_to_df_map[user_selection].keys())] if user_selection is not None else None
)
if __name__ == "__main__":
app.run_server(debug=True)