Adding and removing bootstrap cards to DASH with automatic grid layout in Python

Question:

What I would like to do is when adding a button interactively as in this example (https://github.com/facultyai/dash-bootstrap-components/issues/374#issuecomment-629619851 with this code https://gist.github.com/tcbegley/b7c49d0aec605e383d3b8190448f45f2), to be able to have any kind of grid and not a vertical one where all the cards are stacked on top of each other. I would like to know if you can do so that for example when you create the first card, this is positioned to the left or centre of a first Row, when you create the second one, the first one is moved to the left and the second one is positioned to the right of the first one, making a grid of for example up to 4 rows in this way:

x x
x x
x x
x x

If a card is to be removed, the other cards must be repositioned to leave the gap at the position of the last card.

x x
x x
x x
x 

At the moment it generates the cards vertically 1 below the other. Any ideas on how to do this?

Thanks!

Asked By: carluqcor98

||

Answers:

All you need to do is to replace html.Div([], id="output") with dbc.Row([], style={"width":"850px"},id="output") and everything works seamlessly:

Full example:

import json
import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import ALL, Input, Output, State
from dash.exceptions import PreventUpdate

FONT_AWESOME = "https://use.fontawesome.com/releases/v5.13.0/css/all.css"
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP, FONT_AWESOME])

app.layout = dbc.Container(
    [
        dbc.InputGroup(
            [
                dbc.Input(id="input"),
                dbc.Button("Add card", id="add-button")
            ],
            className="mb-4",
        ),
        dbc.Row([], style={"width":"850px"},id="output"),
    ],
    className="p-5",
)


def make_card(n_add, content):
    return dbc.Card(
        [
            dbc.CardHeader(
                [
                    "Card header",
                    html.Button(
                        html.I(className="fas fa-times"),
                        className="ml-auto close",
                        id={"type": "close-button", "index": n_add},
                    ),
                ]
            ),
            dbc.CardBody(html.P(content, className="card-text")),
        ],
        id={"type": "card", "index": n_add},
        style={"width": "400px"},
        className="mb-3 mx-auto",
    )


@app.callback(
    Output("output", "children"),
    [
        Input("add-button", "n_clicks"),
        Input({"type": "close-button", "index": ALL}, "n_clicks"),
    ],
    [
        State("input", "value"),
        State("output", "children"),
        State({"type": "close-button", "index": ALL}, "id"),
    ],
)
def manage_cards(n_add, n_close, content, children, close_id):
    ctx = dash.callback_context

    if not ctx.triggered:
        raise PreventUpdate
    else:
        button_id, _ = ctx.triggered[0]["prop_id"].split(".")

    if button_id == "add-button":
        if n_add:
            if children is None:
                children = []
            children.append(make_card(n_add, content))
    else:
        print(button_id)
        button_id = json.loads(button_id)
        index_to_remove = button_id["index"]
        children = [
            child
            for child in children
            if child["props"]["id"]["index"] != index_to_remove
        ]

    return children


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

Output:
enter image description here

Answered By: Hamzah
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.