我正在尝试实现一个多页面 Dash webapp,但在跨页面来回切换时,我很难“存储”组件中的更改。即,每次我移动到新页面时,布局都会刷新。
下面有一个(最小的?)代码示例用于重现性目的,其中第 1 页有一个 html 表,第一行允许用户输入和添加按钮,然后也可以删除插入的行。 第 2 页只是一个来回切换的占位符。
我想一种策略可能是拥有不同的
dcc.Store
并记录发生的事情,并在切换时从中填充页面。但我希望有更好的策略 tbh :)
index.py
import dash
from dash import html, dcc
import dash_bootstrap_components as dbc
# Dash app
app = dash.Dash(
__name__,
external_stylesheets=[
dbc.themes.FLATLY,
dbc.icons.BOOTSTRAP,
],
use_pages=True,
)
sidebar = dbc.Col(
id="sidebar",
children=[
dbc.Nav(
id="sidebar-nav",
children=[
dbc.NavLink(children="page1", id="page1", href="/page1", active="exact"),
dbc.NavLink(children="page2", id="page2", href="/page2", active="exact")
],
),
],
)
main_content = dbc.Col(
id="main-content",
className="main-content-expanded",
children=dash.page_container,
)
page = dbc.Row(
id="page",
children=[
sidebar,
main_content,
],
)
url = dcc.Location(id="url", refresh=False)
# App layout
app.layout = html.Div(
id="layout",
children=[page, url],
)
if __name__ == "__main__":
app.run_server(
debug=True,
host=0.0.0.0,
port=8080,
)
pages/page1.py
import dash
import dash_bootstrap_components as dbc
from dash import MATCH, Input, Output, Patch, State, callback, html, dcc
from dash.exceptions import PreventUpdate
dash.register_page(__name__, path="/page1", name="Page1")
def make_filled_row(button_clicked: int, name: str) -> html.Tr:
"""
Creates a filled row in the table, with dynamic id using the button_clicked
parameter.
"""
return html.Tr(
[
html.Td(name),
html.Td(
html.Button(
"Delete",
id={"index": button_clicked, "type": "delete"},
className="delete-user-btn",
)
),
],
id={"index": button_clicked, "type": "table-row"},
)
header = [
html.Thead(
html.Tr(
[
html.Th("First Name"),
html.Th(""),
]
),
id="table-header",
)
]
add_row = html.Tr([
html.Td(dcc.Input(id="name-input")),
html.Td(html.Button("Add", id="add-user-btn",)),
])
body = [html.Tbody([add_row], id="table-body")]
table = html.Table(header + body)
# Layout of the page
layout = dbc.Container([
dbc.Row([dbc.Col([table])]),
])
# List of callbacks for the page
@callback(
Output("table-body", "children", allow_duplicate=True),
Output("name-input", "value"),
Input("add-user-btn", "n_clicks"),
State("name-input", "value"),
prevent_initial_call=True,
)
def on_add(n_clicks: int, name: str):
"""Adds a new row to the table, and clears the input fields"""
table_body = Patch()
table_body.append(make_filled_row(n_clicks, name))
return table_body, ""
@callback(
Output({"index": MATCH, "type": "table-row"}, "children"),
Input({"index": MATCH, "type": "delete"}, "n_clicks"),
prevent_initial_call=True,
)
def on_delete(n_clicks: int) -> html.Tr:
"""Deletes the row from the table"""
if not n_clicks:
raise PreventUpdate
return html.Tr([])
pages/page2.py
import dash
import dash_bootstrap_components as dbc
from dash import html
dash.register_page(__name__, path="/page2", name="Page2")
# Layout of the page
layout = dbc.Container([
dbc.Row([dbc.Col(html.Div("You are on page 2"))]),
])