Create dbc.row with for loop

I’m trying to use a for loop to iterate over a list of field names [fields] to create a series of text dcc.Inputs on consecutive rows. If I move the “for field in fields” line inside dbc.row it works fine but obviously will create inputs side by side. When outside dbc.Row (as in the below) it returns an error, in fact whenever I create any kind of for loop one level below the dbc.Container it creates an error. Is there a rookie mistake I’m making?

layout = html.Div([
    dbc.Container([
        dbc.Row([
            dbc.Col([
                dcc.Input(id='{}'.format(field), type='text', value='{}'.format(field)) 
            ]) 
        ]) for field in fields
    ])
])

Thank you in advance for any help you can provide.

Hi @casual and welcome to the dash community :slightly_smiling_face:

I ran your code and it seemed to work fine. What was the error you were seeing?

Here’s a complete example:



import dash_bootstrap_components as dbc
from dash import Dash,dcc

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

app.layout = dbc.Container([
        dbc.Row([
            dbc.Col([
                dcc.Input(id='{}'.format(field), type='text', value='{}'.format(field))
            ])
        ]) for field in ["a", "b", "c"]
    ])


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

image

1 Like

Hi @AnnMarieW, thank you for the warm welcome and the quick reply!

Running the code in isolation it does actually seem to work, the error seems to occur when I add other components to app.layout outside of those created by the for loop. E.g. if I add a blank dbc.Row() line to the dbc.Container before or after the for loop

import dash_bootstrap_components as dbc
from dash import Dash,dcc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = dbc.Container([
        dbc.Row([]),
        dbc.Row([
            dbc.Col([
                dcc.Input(id='{}'.format(field), type='text', value='{}'.format(field))
            ])
        ]) for field in ["a", "b", "c"]
    ])

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

I suddenly run into ‘SyntaxError: invalid syntax’ pointing at the for loop.

If you are adding a blank row for spacing, I’d recommend using the Bootstrap utility classes instead. You can find more information in this handy Dash Bootstrap Cheatsheet

Here’s an example of adding some margin to the top and bottom of the dcc.Input component using className="my-2":


import dash_bootstrap_components as dbc
from dash import Dash,dcc

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

app.layout = dbc.Container([
        dbc.Row([
            dbc.Col([
                dcc.Input(id='{}'.format(field), type='text', value='{}'.format(field), className="my-2")
            ])
        ]) for field in ["a", "b", "c"]
    ])


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

If you actually do need to repeat another row with content, you would need to add another level of nesting. For example:

import dash_bootstrap_components as dbc
from dash import Dash, dcc

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

app.layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            dbc.Row(dbc.Col("Another Row", className="mt-4")),
            dbc.Row([
                dbc.Col([
                    dcc.Input(
                        id="{}".format(field), type="text", value="{}".format(field)
                    )
                ])
            ])
        ])
    ]) for field in ["a", "b", "c"]
])

if __name__ == "__main__":
    app.run_server(debug=True)
4 Likes

Thank you @AnnMarieW ! As a slight clarification to the above just in case useful for anyone in the future, I was trying to create a series of inputs outside of the for loop that would have configurations distinct from those created and shared in the for loop. Nesting the shared generator in an extra dbc.row/dbc.col and keeping everything else outside of it worked perfectly though, as you suggested!

Many thanks again!

The problem you are facing here is actually a different one, and as such the extra nesting is not necessary. What is going wrong is the list comprehension you are trying to execute. If I copy your original code into my Pycharm IDE, it already tells me that there is an error with my syntax. Let me demonstrate with a small example, consider the following code snippet:

[0, a for a in range(1, 5)]
>>> SyntaxError

First you manually add a number, and then you complete the list using a list comprehension.
This code won’t execute correctly because list comprehensions don’t work on a sub part of the list. The comprehension needs to be the only thing enclosed in brackets, like this:

[a for a in range(1, 5)]
>>> [1, 2, 3, 4]

So what if we still want to do something like the first snippet (which is what you are intending to do)? Actually, the solution is easy, you create a list inside the list and then you unpack the inner list again, like this:

[0, *[a for a in range(1, 5)]]
>>> [0, 1, 2, 3, 4]

See below example to make your code working using above list unpacking trick:

import dash_bootstrap_components as dbc
from dash import Dash,dcc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = dbc.Container([
        dbc.Row([dbc.Col('Another row')]),
        *[dbc.Row([
            dbc.Col([
                dcc.Input(id='{}'.format(field), type='text', value='{}'.format(field))
            ])
        ]) for field in ["a", "b", "c"]]
    ])

if __name__ == "__main__":
    app.run_server(debug=True)
2 Likes