隐藏动态更新的区块

问题描述 投票:0回答:1

我有一个破折号应用程序。它的本质是每30秒向数据库发出一次请求,并根据它们更新页面。数据被分为11个块,其中一些可能是空的。如果它们是空的,那么我就不会完全显示它。

每个块都有一个带有标题 (1) 的行和一个包含行 (2) 的表格(屏幕截图)。

我需要在标题栏添加一个按钮来隐藏表格 (2)。我通过带有索引的按钮回调来完成此操作。

@callback(
    Output({"type": "dynamic-card", "index": MATCH}, "style"),
    Input({"type": "dynamic-button", "index": MATCH}, "n_clicks")
)

但是由于每次都会出现新数据并创建新块,我都会重新创建按钮。因此,他们的

n_clicks = 0
和隐藏的方块再次显露出来。

我尝试将每个按钮的

n_clicks
写入文件并在更新之前读取它们。但事实证明,隐藏对于所有用户来说都是相同的,但我需要为每个用户单独隐藏。

我的问题是更新后如何保存

n_clicks
(并且每个用户在会话期间保持隐藏状态)。

我的代码(为了方便,删除了所有样式的导入,页面如图截图):

from dash import dcc, html, Input, Output, callback, MATCH, ctx
from datetime import datetime
import dash_bootstrap_components as dbc

refreshing_data = [
    [],
    [],
    [],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    [],
    [],
    [],
    [],
    [],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    'Last refresh at 15:19'
]

switch_case = {
    0: 'H0',
    1: 'H1',
    2: 'H2',
    3: 'H3',
    4: 'H4',
    5: 'H5',
    6: 'H6',
    7: 'H7',
    8: 'H8',
    9: 'H9',
    10: 'H10'
}


def template_small_card(row):
    date_req = row[1]
    operation = row[2]
    link = row[3]
    status = row[4]
    card = html.Div([
        html.H6("Content is {}, {}, {}, {}".format(date_req, operation, link, status))
    ],
    )
    return card


def template_big_card(list_of_small_cards, big_name):
    n = big_name
    card = html.Div(
        [
            html.Div([
                # button to hide the block
                html.Div(
                    [
                        html.Button(children=[html.Img(src='assets/vector1.png')],
                                    n_clicks=0,
                                    id={"type": "dynamic-button", "index": n},
                                    ),
                    ],
                ),
                html.Div([
                    html.H4("{}".format(big_name), className="card-title", ),
                ], ),
            ],
            ),
            html.Hr(),
            # I plan to hide this block
            html.Div([
                *list_of_small_cards
            ],
                id={"type": "dynamic-card", "index": n}
            )
        ],
    )
    return dbc.Row(children=[card], className="g-0")


def generate_big_card(data, big_name):
    if not data:
        return []
    else:
        result = []
        for ind in data:
            small_card = template_small_card(ind)
            result.append(small_card)
        big_card = template_big_card(result, switch_case[big_name])
        return big_card


layout = html.Div([
    html.Div('Request queue'),
    html.H6(id='time_update_1_vert'),
    dcc.Interval(
        id='interval-component_vert',
        interval=30 / 60 * 60000,
        n_intervals=0
    ),
    dbc.Row(id='row-tables_vert')
],
)


@callback(
    Output('time_update_1_vert', 'children'),
    Output('row-tables_vert', 'children'),
    Input('interval-component_vert', 'n_intervals'),
)
def update_data(n_intervals):
    list_of_df = refreshing_data
    columns_for_row = []
    time_update = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
    for i in range(0, 11):
        dbc_column = generate_big_card(list_of_df[i], i)
        if dbc_column:
            columns_for_row.append(dbc_column)
    return time_update, columns_for_row


@callback(
    Output({"type": "dynamic-card", "index": MATCH}, "style"),
    Input({"type": "dynamic-button", "index": MATCH}, "n_clicks")
)
def update_card(n_clicks):
    if n_clicks % 2 == 1:
        style1 = {'display': 'none'}
    else:
        style1 = {}
    return style1

python plotly-dash
1个回答
0
投票

普遍的问题是在回调之间共享数据。这是通过

dcc.Store
组件解决的。

卡的当前可见性可能存储在那里。我们假设默认情况下所有卡片都是可见的。

session_cards_visibility = dbc.Container([
    dcc.Store(
        id={'type': 'session_card_visibility', 
            'index': switch_case[index]},
        data=True,  # True means visible
        storage_type='session') for index in range(len(switch_case))
    ])

# ...

# somewhere in the layout:
layout = [
    # ...
    session_cards_visibility,
    html.Div('Request queue'),
    html.H6(id='time_update_1_vert'),
    # ...

统计按钮点击次数似乎不太可靠。显示/隐藏逻辑最好通过切换(即按钮)来表示。因此,在示例中,按钮被替换为

dbc.Checklist
,并且是唯一的选项。

# in template_big_card() instead of html.Button
dbc.Checklist(
    id={"type": "dynamic-button", "index": n},
    options=[{"label": f"Option {n}", "value": True}],
    value=[True] if visible else [],  # visible - see below
    inline=True,
    switch=True)

可以根据当前的切换状态显示或隐藏卡片,并更新相应的会话存储。

@app.callback(
    Output({'type': 'dynamic-card', 'index': MATCH}, 'hidden'),
    Output({'type': 'session_card_visibility', 'index': MATCH}, 'data'),
    Input({'type': 'dynamic-button', 'index': MATCH}, 'value'),
    prevent_initial_call=True)
def update_card(toggle_options):  # toggle_options - is a list
    
    show_card = bool(toggle_options)  # value is chosen [True] or not []
    return (
        not show_card,  # hidden=True must be similar to style={'display': 'none'}
        show_card  # save the value in the session store
    )

最后,

update_data()
应该获取所有存储的值并将它们作为参数传递给
generate_big_card()
template_big_card()

@app.callback(
    Output('time_update_1_vert', 'children'),
    Output('row-tables_vert', 'children'),
    Input('interval-component_vert', 'n_intervals'),
    State({"type": "session_card_visibility", "index": ALL}, "data"))
def update_data(_, visibilities):
    # ...
    for i in range(0, 11):
        dbc_column = generate_big_card(list_of_df[i], i, visibilities[i])
    # ...


def generate_big_card(data, big_name, visible):
    # ...
    big_card = template_big_card(result, switch_case[big_name], visible)
    # ...


def template_big_card(list_of_small_cards, big_name, visible=True):
    # ... set the toggle state as was mentioned above

    html.Div([*list_of_small_cards],
        id={"type": "dynamic-card", "index": n},
        hidden=not visible  # hide the card if necessary
    )
© www.soinside.com 2019 - 2024. All rights reserved.