Dropdown and Layout Change. Callback not responding to dropdown option

Am using dash 2.9.2. I came across curious case of dcc.Dropdown option not triggering callback.
Here is simple dash code : (I built this for changing layout from 3 Rows to 2 Rows based on Dropdown). It starts with 3Row layout. When I select 2Rows option, it responds correctly. However after that when I click 3Rows, nothing happens.

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

ddown = dcc.Dropdown(id='dropdown', 
        options=[
                {'label': '3-Rows', 'value': '3_Rows'},
                {'label': '2-Rows', 'value': '2_Rows'},],
                 value='3Rows')         
                #placeholder='Select One') #value='3_Rows')#
rowr1 = dbc.Row([dbc.Col(children="This is R1 C1", class_name='r1c1'),
                     dbc.Col(children="This is R1 C2", class_name='r1c2'),
                     dbc.Col(children=ddown, class_name='r1c3')], class_name='r1 g-0')

def layout3():
    global rowr1
    rowr2 = dbc.Row([dbc.Col(children="This is R2 C1", class_name='r2c1'),
                     dbc.Col(children="This is R2 C2", class_name='r2c2')],class_name='r2 g-0')

    rowr3 = dbc.Row([dbc.Col(children="This is R3 C1", class_name='r3c1'),
                     dbc.Col(children="This is R3 C2", class_name='r3c2')],class_name='r3 g-0')
    layout = [rowr1, rowr2, rowr3]
    return layout 

def layout2():
    global rowr1
    rowr2 = dbc.Row([dbc.Col(children="This is R2 C1", class_name='r2c1'),
                     dbc.Col(children="This is R2 C2", class_name='r2c2')],class_name='r2 g-0')
    layout = [rowr1, rowr2]
    return layout 

layout = layout3()
app.layout = dbc.Container(id ='main', children=layout,class_name='container')

@app.callback(
    Output('main','children'),
    [Input('dropdown','value')], prevent_initial_call=True
)
def update_lay(ddvalue):
    if ddvalue == '3_Rows':
        layout = layout3()
        return layout
    elif ddvalue == '2_Rows':
        layout=layout2()
        return layout

Suppress Werkzeug logging output

import logging
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR) 

if __name__ == "__main__":
    app.run(port=8888, use_reloader=False)

I found a workaround by commenting in Dropdown code "value=‘3_Rows’) and replaced with 'placeholder=‘Select One’) and it works !!!.

I haven’t understood why. Am I missing something ??
Though problem got resolved, welcome comments for further understanding.
Cheers.

Hi, did you try running in debug=true?

Thanks for your response. I tried, but no help. Request you to copy code and try on your machine and let me know. Am using win64.
Cheers. Have a nice day ahead.

Did you get an error message?

I actually don’t know what exactly is the question now, but you should select a value from the options, in this case it would be 3_Rows instead of 3Rows

I think the problem here is that you don’t fix rowr1 but let it run according to the dropdown value, so every time you change the value of the dropdown, the layout will run rowr1 again and the dropdown value will be 3_Rows again.

I think you could change as below to make it work.

import pandas as pd
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
import dash

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

ddown = dcc.Dropdown(id='dropdown', 
        options=[
                {'label': '3-Rows', 'value': '3_Rows'},
                {'label': '2-Rows', 'value': '2_Rows'}],
                 value='3_Rows', placeholder='Select One') #value='3_Rows')#

rowr1 = dbc.Row([
    dbc.Col(
        children="This is R1 C1", class_name='r1c1'),
    dbc.Col(
        children="This is R1 C2", class_name='r1c2'),
    dbc.Col(
        children=ddown, class_name='r1c3')], class_name='r1 g-0')

rowr2 = dbc.Row([
    dbc.Col(
        children="This is R2 C1", class_name='r2c1'),
    dbc.Col(
        children="This is R2 C2", class_name='r2c2')],class_name='r2 g-0')

rowr3 = dbc.Row([
    dbc.Col(
        children="This is R3 C1", class_name='r3c1'),
    dbc.Col(
        children="This is R3 C2", class_name='r3c2')],class_name='r3 g-0')


app.layout = dbc.Container([
    rowr1, 
    html.Div(id='main')
])

@app.callback(
    Output('main','children'),
    [Input('dropdown','value')]
)
def update_lay(ddvalue):
    if ddvalue == '3_Rows':
        layout = [rowr2,rowr3]
        return layout
    else:
        layout=[rowr2]
        return layout  
if __name__ == '__main__':
    app.run_server(debug=False, use_reloader=False)

Recording 2023-04-06 134804

Dear Tran Khanh Hoa,
Thanks. I agree, keeping rowr1 outside avoids handling it thro’ callbacks.
This resolves. Thanks for your time and guidance.

By the way, did you get same issue of not able to revert to 3 rows after selecting 2 rows once ???
Cheers.

1 Like

Did you try to run my code? I didn’t get that error.

Dear Tran Khanh Hoa,
Sorry for the confusion. No error on your code. Works Perfect.

I was curious if you got the same error of not able to select 3 rows again after selecting 2 rows in code that I posted.

Yep, I got same error as your, so as I said, I think problem comes from rowr1 that be created by dropdown.

You are right. However this is not the issue.
Problem is that initial layout is for 3 rows. When I select 2 Rows option in dropdown, layout changes correctly to 2 Rows (callback is fired). However now, if I select 3 rows thro dropdown, it does not change…

Incidently Tran Khanh Hoa has solved the issue. Row1 is unchanged in both the options so, removed the same while updating from callback.