Learn how to use Dash Bio for next-gen sequencing & quality control. 🧬 Register for the Oct 27 webinar.

App.callback not working in program called using dash bootstrap

I’m trying to use dash bootstrap for the first time. I’m using their simple sidebar code to create a main page. One of our options will be for someone to send us an email with questions. I’ve created the screen for it (name, email address and question/comment) along with a submit button. When someone clicks on the submit button an email is sent. Nothing happens. I’ve banged my head against the wall for a while and figured that I’d reach out to the community. Thanks in advance.

App.py (code from dash bootstrap):
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import contact_us as contact_us
import welcome as welcome
import calc_portfolio as calc_portfolio

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

the style arguments for the sidebar. We use position:fixed and a fixed width

SIDEBAR_STYLE = {
“position”: “fixed”,
“top”: 0,
“left”: 0,
“bottom”: 0,
“width”: “18rem”,
“padding”: “2rem 1rem”,
“background-color”: “#f8f9fa”,
}

the styles for the main content position it to the right of the sidebar and

add some padding.

CONTENT_STYLE = {
“margin-left”: “18rem”,
“margin-right”: “2rem”,
“padding”: “2rem 1rem”,
}

sidebar = html.Div(
[
html.P(“Robo Investing Tool”, className=“display-4”),
html.Hr(),
# html.P(
# “Robo Investing Tool”, className=“lead”
# ),
dbc.Nav(
[
dbc.NavLink(“Welcome”, href="/page-1", id=“page-1-link”),
dbc.NavLink(“Create a portfolio”, href="/page-2", id=“page-2-link”),
dbc.NavLink(“Contact Us”, href="/page-3", id=“page-3-link”),
dbc.NavLink(“FAQ”, href="/page-4", id=“page-4-link”),
],
vertical=True,
pills=True,
),
],
style=SIDEBAR_STYLE,
)

content = html.Div(id=“page-content”, style=CONTENT_STYLE)

app.layout = html.Div([dcc.Location(id=“url”), sidebar, content])

this callback uses the current pathname to set the active state of the

corresponding nav link to true, allowing users to tell see page they are on

@app.callback(
[Output(f"page-{i}-link", “active”) for i in range(1, 4)],
[Input(“url”, “pathname”)],
)
def toggle_active_links(pathname):
if pathname == “/”:
# Treat page 1 as the homepage / index
return True, False, False
return [pathname == f"/page-{i}" for i in range(1, 4)]

@app.callback(Output(“page-content”, “children”),
[Input(“url”, “pathname”)]
)
def render_page_content(pathname):
if pathname in ["/", “/page-1”]:
return welcome.welcome

elif pathname == "/page-2":
    return calc_portfolio.get_data

elif pathname == "/page-3":
    return contact_us.email

elif pathname == '/page-4':
    return html.P('Welcome to the FAQ Page')

if name == “main”:
app.run_server(debug=True)

My program contact_us.py…

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

import smtplib
import mimetypes
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

email = html.Div(
[
dbc.Form(
[
dbc.FormGroup(
[
dbc.Label(‘To send us a comment please fill out the information below’),
html.Br(),
dbc.Label(‘Name:’),
dbc.Input(
type = ‘text’,
id = ‘name’,
minLength = 3,
maxLength = 100,
valid = True,
style = {‘width’: 400}
),
],
),
dbc.FormGroup(
[
dbc.Label(‘Email address:’),
dbc.Input(
type=“email”,
id=‘email-addr’,
minLength = 5,
maxLength = 30,
valid = True,
style = {‘width’: 400}
),
],
),
dbc.FormGroup(
[
html.Br(),
html.Br(),
dbc.Label(‘Please type your comment below:’),
html.Br(),
dbc.Label(‘Minimum 10 characters, maximum 1,000 characters’),
dbc.Textarea(
# type = ‘text’,
id = ‘comment’,
maxLength = 1000,
required = True,
rows = 10,
spellCheck = True,
valid = True
),
],
),
dbc.Button(‘Submit’,
id = ‘submit-email’,
color = ‘primary’,
n_clicks = 0
),
],
), html.Div(id = ‘email-message’),
])

@app.callback(
[Output(‘email-message’, ‘children’)],
[Input(‘submit-email’, ‘n_clicks’)],
[State(‘name’, ‘text’),
State(‘email-addr’, ‘email’),
State(‘comment’, ‘text’)]
)

def on_button_click(n_clicks, test_name, email_addr, test_comment):
# if n_clicks is None:
# pass

print('in sendmail function')
msg = MIMEMultipart()
msg["From"] = email_addr
msg["To"] = 'pkoppelman@yahoo.com'
msg["Subject"] = "Robo Investing Question"
body = MIMEText('This is a test of the robo investing email system')
msg.attach(body)

ctype, encoding = mimetypes.guess_type(email_reference.filetosend)
if ctype is None or encoding is not None:
    ctype = "application/octet-stream"

maintype, subtype = ctype.split("/", 1)

if maintype == "text":
    fp = open(email_reference.filetosend)
    # Note: we should handle calculating the charset
    attachment = MIMEText(fp.read(), _subtype=subtype)
    fp.close()
elif maintype == "image":
    fp = open(email_reference.filetosend, "rb")
    attachment = MIMEImage(fp.read(), _subtype=subtype)
    fp.close()
elif maintype == "audio":
    fp = open(email_reference.filetosend, "rb")
    attachment = MIMEAudio(fp.read(), _subtype=subtype)
    fp.close()
else:
    fp = open(email_reference.filetosend, "rb")
    attachment = MIMEBase(maintype, subtype)
    attachment.set_payload(fp.read())
    fp.close()
    encoders.encode_base64(attachment)

attachment.add_header(“Content-Disposition”, “attachment”, filename=email_reference.filetosend)

# msg.attach(attachment)

# Send the email - if you get an error that says Username and Password not accepted, please go to the 
# gmail account that is sending the email and choose 'Less secure app access'. Gmail does not like
# smtplib - Peter Koppelman March 25, 2020
try:
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login(email_reference.emailfrom, email_reference.password)
    server.sendmail(email_reference.emailfrom, email_reference.distribution_list, msg.as_string())
    server.close()
    message = True
except:
    message = False