Input callback returns None if modifying children of html.Div

Hello everyone! The following code here unfortunately doesnt work as expected:

The callback function display_page() never detects the value of the username properly, and instead always detect the value of user as None:

import bcrypt
import dash_bootstrap_components as dbc
from dash import Dash, dcc, html, Input, Output, callback, State

# if you don't include the external_stylesheets the alignment may not work
external_stylesheets = [dbc.themes.BOOTSTRAP]
app = Dash(__name__, external_stylesheets=external_stylesheets)

username = "abcd"
hashed_password = b'$2b$12$.0I25Y7fsYdzaJhSqZph5eVgYSKF8HClM1G4WOAqVd01CqKgTvX26'


def get_hashed_password(passwd: str) -> bytes:
    return bcrypt.hashpw(str.encode(passwd), b"$2b$12$.0I25Y7fsYdzaJhSqZph5e")


login_text_style = {
    "width": "400px",
    "height": "20px",
    "padding": "10px",
    "padding-left": "20px",
    "margin-top": "15px",
    "font-size": "15px",
    "border-width": "2px",
    "border-radius": "20px",
    "border-color": "#CFCFCF",
    "border-style": "solid",
}
login_button_style = {
    "width": "100px",
    "font-size": "14px",
    "margin-top": "5px",
    "margin-left": "330px",
    "border-width": "2px",
    "padding": "10px",
    "background-color": "#CCCCCC",
    "color": "#303030",
    "border-radius": "20px",
    "border-color": "#FFFFFF",
    "border-style": "solid",
}

login_part = [
    html.Div(
        dcc.Input(
            id="user-input",
            type="text",
            placeholder="Username",
            className="inputbox1",
            style=login_text_style,
        ),
    ),
    html.Div(
        dcc.Input(
            id="passw-input",
            type="password",
            placeholder="Password",
            className="inputbox2",
            debounce=True,
            style=login_text_style,
        ),
    ),
    html.Div(
        [
            html.Button(
                "Verify",
                id="verify-button",
                n_clicks=0,
                style=login_button_style,
            ),
        ]
    )
]

dashboard_part = html.Div(
                children="Dashboard here!",
                id="dashboard-text",
                style={"color": "#000000"},
            )
# create a layout with the dropdown, a blank like and an empty space where the result of the selection would be
app.layout = html.Div(children=login_part, id="page-id")


@callback(
    Output(component_id="page-id", component_property="children"),
    [Input("verify-button", "n_clicks"),
     State("user-input", "value"),
     State("passw-input", "value")]
)
def display_page(n_clicks, user, passw):
    passw = passw or ""
    # success login, jump to graphs
    # TODO fix reading username
    if user == username and get_hashed_password(passw) == hashed_password:
        return dashboard_part
    return login_part


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

One funny thing it that, if I make the callback to just update a component e.g. text of the button, instead of changing the entire page, this bug doesn’t exists at all

Try by changing the callback into:

@callback(
    Output(component_id="verify-button", component_property="children"),
    [Input("verify-button", "n_clicks"),
     State("user-input", "value"),
     Input("passw-input", "value")]
)
def display_page(n_clicks, user, passw):
    passw = passw or ""
    # success login, jump to graphs
    # TODO fix reading username
    if user == username and get_hashed_password(passw) == hashed_password:
        return "success"
    return "fail"

username: abcd
password: abcd

Thanks for the help!

Hey @user_here , welcome to the forums!

Try returning no_update instead of login_part. You have to import it from dash.

1 Like

this works, thanks!

1 Like